cloudflare / speedtest

Component to perform network speed tests against Cloudflare's edge network
https://speed.cloudflare.com
MIT License
459 stars 34 forks source link

Download bandwidth test not working #15

Closed jamesthesken closed 1 year ago

jamesthesken commented 1 year ago

Edit Looks like the problem only occurs in Safari v16.4

Hello, thank you for making this great tool. I am building a Next.js app to collect speed test surveys and this is perfect.

For some reason, my download bandwidth result is working fine on https://speed.cloudflare.com, but not in my own code. The upload test works fine in the following code as well.

Any thoughts? Thank you in advance for any insight.

"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import SpeedTest from "@cloudflare/speedtest";

export default async function Home() {
  const [speedTestResults, setSpeedTestResults] = useState<any>();

  const config = {
    autoStart: false,
    measurements: [
      { type: "latency", numPackets: 1 }, // initial latency estimation
      { type: "download", bytes: 1e5, count: 1, bypassMinDuration: true }, // initial download estimation
      { type: "latency", numPackets: 20 },
      { type: "download", bytes: 1e5, count: 9 },
      { type: "download", bytes: 1e6, count: 8 },
      { type: "upload", bytes: 1e5, count: 8 },
      { type: "packetLoss", numPackets: 1e3, responsesWaitTime: 3000 },
      { type: "upload", bytes: 1e6, count: 6 },
      { type: "download", bytes: 1e7, count: 6 },
      { type: "upload", bytes: 1e7, count: 4 },
      { type: "download", bytes: 2.5e7, count: 4 },
      { type: "upload", bytes: 2.5e7, count: 4 },
      { type: "download", bytes: 1e8, count: 3 },
      { type: "upload", bytes: 5e7, count: 3 },
      { type: "download", bytes: 2.5e8, count: 2 },
    ],
  };

  const safeFetch = async (url: any, options = {}) => {
    try {
      const request = await fetch(url, options);
      const json = JSON.parse(await request.text());
      const headers = await request.headers;
      return { json, headers };
    } catch (_) {
      return {};
    }
  };

  const runSpeedTest = async () => {
    const ua = { user_agent: window.navigator.userAgent };
    const meta = (await safeFetch("https://speed.cloudflare.com/meta")).json;
    const { utc_datetime, unixtime } = (
      await safeFetch("https://worldtimeapi.org/api/timezone/Etc/UTC")
    ).json;
    const ts = { epoch: unixtime, dateTime: utc_datetime };

    const engine = new SpeedTest(config as any);

    engine.onResultsChange = (results) => {
      const summary = engine.results.getSummary();
      const scores = engine.results.getScores();
      setSpeedTestResults({ ...scores, ...summary, ...meta, ...ts, ...ua });
      console.log(speedTestResults);
    };

    engine.onFinish = (results) => {
      const summary = results.getSummary();
      const scores = results.getScores();

      setSpeedTestResults({ ...scores, ...summary, ...meta, ...ts, ...ua });
      console.log(speedTestResults);
      const finishedElement = document.createElement("div");
      finishedElement.id = "speedtest-finished";
      document.body.appendChild(finishedElement);
      console.log("done");
      console.log(results.getDownloadBandwidth());
    };

    console.log("running");

    engine.play();
  };

  useEffect(() => {
    runSpeedTest();
  }, []);

  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
        {speedTestResults && (
          <div>
            <h1>Speed Test Results:</h1>
            <pre>{JSON.stringify(speedTestResults, null, 2)}</pre>
          </div>
        )}
      </div>
    </main>
  );
}

The speed test from the above code results in:

Speed Test Results:
{
  "streaming": {
    "points": 5,
    "classificationIdx": 0,
    "classificationName": "bad"
  },
  "gaming": {
    "points": 5,
    "classificationIdx": 1,
    "classificationName": "poor"
  },
  "rtc": {
    "points": 15,
    "classificationIdx": 2,
    "classificationName": "average"
  },
  "download": 0,
  "upload": 11065235.342691988,
  "latency": 104.5001764999999,
  "jitter": 2.3158093157894624,
  "downLoadedLatency": 110.49997649999636,
  "downLoadedJitter": 4.947327684205933,
  "upLoadedLatency": 125.50001699999636,
  "upLoadedJitter": 119.36841721052556,
  "packetLoss": 0,
  "hostname": "speed.cloudflare.com",
  "httpProtocol": "HTTP/1.1",
  "country": "US",
  "epoch": 1684272979,
  "dateTime": "2023-05-16T21:36:19.066248+00:00",
}
numberslk commented 1 year ago

We are experiencing the same issue that seems to be occurring exclusively on Apple devices, specifically in Safari and Chrome browsers. The problem does not appear when accessing from other mobile devices or browsers.

jamesthesken commented 1 year ago

Interesting.. It is working on my MacBook using Chrome Version 113.0.5672.126 (Official Build) (x86_64)

vasturiano commented 1 year ago

@jamesthesken thanks for reaching out and filing this issue.

We've open a PR which addresses this and also provides more background information as to why this is happening.

jamesthesken commented 1 year ago

@jamesthesken thanks for reaching out and filing this issue.

We've open a PR which addresses this and also provides more background information as to why this is happening.

Thank you for taking the time to address the issue and background!

One day I'll try to implement the template to get around those CORS issues - https://github.com/cloudflare/worker-speedtest-template