Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ class SpeedTestEngine extends MeasurementEngine {
}
logFinalResults(results, {
apiUrl,
includeCredentials: this.config.includeCredentials,
sessionId: this.config.sessionId,
authorization: this.authorization
}).then(response => {
Expand Down
7 changes: 5 additions & 2 deletions src/logging/logFinalResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface ScoreEntry {
interface LogConfig {
/** URL to POST the results to. */
apiUrl: string;
/** Whether to include credentials in the request. */
includeCredentials: boolean;
/** Session ID to include in the log payload. */
sessionId: string | undefined;
/** Token attributing this test, sent as an `Authorization` header. */
Expand Down Expand Up @@ -111,7 +113,7 @@ const scoreParser = (
*/
const logAimResults = async (
results: Results,
{ apiUrl, sessionId, authorization }: LogConfig
{ apiUrl, includeCredentials, sessionId, authorization }: LogConfig
): Promise<AimLogResponse> => {
const logData: LogData = {
sessionId
Expand Down Expand Up @@ -142,7 +144,8 @@ const logAimResults = async (
withAuthorizationHeader(
{
method: 'POST',
body: JSON.stringify(logData)
body: JSON.stringify(logData),
credentials: includeCredentials ? 'include' : 'same-origin'
},
authorization,
apiUrl
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/logging/logFinalResults.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const makeResults = (): Results =>

const config = {
apiUrl: 'https://aim.example.com/__results',
includeCredentials: false,
sessionId: undefined,
authorization: null
};
Expand All @@ -42,11 +43,26 @@ describe('logAimResults', () => {
const [url, init] = fetchMock.mock.calls[0];
expect(url).toBe(config.apiUrl);
expect(init.method).toBe('POST');
expect(init.credentials).toBe('same-origin');
// The module's main job is formatting logData — assert it lands in the body.
const body = JSON.parse(init.body);
expect(body.totalDurationMs).toBe(1234);
});

it('includes credentials when configured', async () => {
const fetchMock = vi
.fn()
.mockResolvedValue(new Response('{}', { status: 200 }));
vi.stubGlobal('fetch', fetchMock);

await logAimResults(makeResults(), {
...config,
includeCredentials: true
});

expect(fetchMock.mock.calls[0][1].credentials).toBe('include');
});

it('resolves with the parsed response body (e.g. requestId)', async () => {
const requestId = '11111111-2222-3333-4444-555555555555';
vi.stubGlobal(
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/resultsLogging.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import SpeedTest from '../../src';

describe('final results logging', () => {
afterEach(() => {
vi.unstubAllGlobals();
});

it('propagates includeCredentials to the results request', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response('{}', {
headers: { 'content-type': 'application/json' },
status: 200
})
);
vi.stubGlobal('fetch', fetchMock);

const engine = new SpeedTest({
autoStart: false,
includeCredentials: true,
logAimApiUrl: 'https://example.com/__results',
measurements: []
});
const logged = new Promise<void>(resolve => {
engine.onResultsLogged = () => resolve();
});

engine.play();
await logged;

expect(fetchMock).toHaveBeenCalledOnce();
expect(fetchMock.mock.calls[0][1].credentials).toBe('include');
});
});
Loading