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
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ updates:
vitest:
patterns:
- 'vitest'
- '@cloudflare/vitest-pool-workers'
- '@cloudflare/vitest-plugin'
ignore:
- dependency-name: nodejs-latest-linker
47 changes: 24 additions & 23 deletions e2e-tests/directory.kv.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { env, createExecutionContext } from 'cloudflare:test';
import { createExecutionContext } from 'cloudflare:test';
import { env } from 'cloudflare:workers';
import { test, beforeAll, expect, vi } from 'vitest';
import {
populateDirectoryCacheWithDevBucket,
Expand All @@ -15,31 +16,31 @@ const mockedEnv: Env = {
USE_KV: true,
};

vi.mock(
import('../src/constants/latestVersions.json'),
async importOriginal => {
const original = await importOriginal();

// Point all `latest-` directories to one that exists in the dev bucket
Object.keys(original.default).forEach(branch => {
let updatedValue: string;
if (branch === 'node-latest.tar.gz') {
updatedValue = 'latest/node-v20.0.0.tar.gz';
} else {
updatedValue = 'v20.0.0';
}

// @ts-expect-error
original.default[branch] = updatedValue;
});

return original;
}
);

beforeAll(async () => {
await populateR2WithDevBucket();
await populateDirectoryCacheWithDevBucket();

vi.mock(
import('../src/constants/latestVersions.json'),
async importOriginal => {
const original = await importOriginal();

// Point all `latest-` directories to one that exists in the dev bucket
Object.keys(original.default).forEach(branch => {
let updatedValue: string;
if (branch === 'node-latest.tar.gz') {
updatedValue = 'latest/node-v20.0.0.tar.gz';
} else {
updatedValue = 'v20.0.0';
}

// @ts-expect-error
original.default[branch] = updatedValue;
});

return original;
}
);
});

// Ensure essential endpoints are routable
Expand Down
57 changes: 36 additions & 21 deletions e2e-tests/directory.s3.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { env, fetchMock, createExecutionContext } from 'cloudflare:test';
import { test, beforeAll, afterEach, expect } from 'vitest';
import { createExecutionContext } from 'cloudflare:test';
import { env } from 'cloudflare:workers';
import { test, beforeAll, beforeEach, afterEach, expect, vi } from 'vitest';
import type { MockInstance } from 'vitest';
import { populateR2WithDevBucket } from './util';
import worker from '../src/worker';
import type { Env } from '../src/env';
Expand Down Expand Up @@ -45,17 +47,37 @@ const S3_EMPTY_DIRECTORY_RESULT = `
<IsTruncated>false</IsTruncated>
</ListBucketResult>`;

beforeAll(async () => {
fetchMock.activate();
fetchMock.disableNetConnect();
let fetchSpy: MockInstance<typeof fetch>;

beforeAll(async () => {
await populateR2WithDevBucket();
});

beforeEach(() => {
fetchSpy = vi
.spyOn(globalThis, 'fetch')
.mockRejectedValue(new Error('Unexpected outbound request'));
});

afterEach(() => {
fetchMock.assertNoPendingInterceptors();
vi.restoreAllMocks();
});

function mockS3Response(body: string, prefix?: string): void {
fetchSpy.mockImplementationOnce(async (input, init) => {
const url = new URL(new Request(input, init).url);

if (
url.origin !== s3Url.origin ||
(prefix !== undefined && url.searchParams.get('prefix') !== prefix)
) {
throw new Error(`Unexpected request to ${url}`);
}

return new Response(body);
});
}

// These paths are cached and don't send requests to S3
for (const path of ['/dist/', '/docs/']) {
test(`GET \`${path}\` returns 200`, async () => {
Expand All @@ -75,17 +97,13 @@ for (const path of ['/dist/', '/docs/']) {
expect(res.headers.get('cache-control')).toStrictEqual(
CACHE_HEADERS.mutable
);
expect(fetchSpy).not.toHaveBeenCalled();
});
}

for (const path of ['/api/', '/download/', '/metrics/']) {
test(`GET \`${path}\` returns 200`, async () => {
fetchMock
.get(s3Url.origin)
.intercept({
path: /.*/,
})
.reply(200, S3_DIRECTORY_RESULT);
mockS3Response(S3_DIRECTORY_RESULT);

const ctx = createExecutionContext();

Expand All @@ -99,19 +117,15 @@ for (const path of ['/api/', '/download/', '/metrics/']) {
await res.text();

expect(res.status).toBe(200);
expect(fetchSpy).toHaveBeenCalledOnce();
});
}

test('GET `/dist/unknown-directory/` returns 404', async () => {
fetchMock
.get(s3Url.origin)
.intercept({
path: /.*/,
query: {
prefix: 'nodejs/release/unknown-directory/',
},
})
.reply(200, S3_EMPTY_DIRECTORY_RESULT);
mockS3Response(
S3_EMPTY_DIRECTORY_RESULT,
'nodejs/release/unknown-directory/'
);

const ctx = createExecutionContext();

Expand All @@ -124,6 +138,7 @@ test('GET `/dist/unknown-directory/` returns 404', async () => {
expect(res.status).toBe(404);
expect(res.headers.get('cache-control')).toStrictEqual(CACHE_HEADERS.failure);
expect(await res.text()).toStrictEqual('Directory not found');
expect(fetchSpy).toHaveBeenCalledOnce();
});

test('GET `/dist` redirects to `/dist/`', async () => {
Expand Down
3 changes: 2 additions & 1 deletion e2e-tests/file.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { env, createExecutionContext } from 'cloudflare:test';
import { createExecutionContext } from 'cloudflare:test';
import { env } from 'cloudflare:workers';
import { test, beforeAll, afterEach, expect, vi } from 'vitest';
import { populateR2WithDevBucket } from './util';
import worker from '../src/worker';
Expand Down
10 changes: 6 additions & 4 deletions e2e-tests/misc.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { env, fetchMock, createExecutionContext } from 'cloudflare:test';
import { test, beforeAll, expect } from 'vitest';
import { createExecutionContext } from 'cloudflare:test';
import { env } from 'cloudflare:workers';
import { test, beforeAll, expect, vi } from 'vitest';
import { populateR2WithDevBucket } from './util';
import worker from '../src/worker';
import type { Env } from '../src/env';
Expand All @@ -11,8 +12,9 @@ const mockedEnv: Env = {
};

beforeAll(async () => {
fetchMock.activate();
fetchMock.disableNetConnect();
vi.spyOn(globalThis, 'fetch').mockRejectedValue(
new Error('Unexpected outbound request')
);

await populateR2WithDevBucket();
});
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"compilerOptions": {
"types": [
"../worker-configuration.d.ts",
"@cloudflare/vitest-pool-workers",
"@cloudflare/vitest-plugin/types",
"../vitest-types.d.ts"
]
},
Expand Down
12 changes: 7 additions & 5 deletions e2e-tests/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { env } from 'cloudflare:test';
import { env } from 'cloudflare:workers';
import { join } from 'node:path';
import { inject } from 'vitest';
import type { Env } from '../src/env';
import type { Env as WorkerEnv } from '../src/env';
import type { Directory } from '../vitest-setup';
import type { ReadDirectoryResult, File } from '../src/providers/provider';

Expand Down Expand Up @@ -83,7 +83,9 @@ export async function populateDirectoryCacheWithDevBucket(): Promise<void> {
await populateDirectoryCache(devBucket);
}

declare module 'cloudflare:test' {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface ProvidedEnv extends Env {}
declare global {
namespace Cloudflare {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface Env extends WorkerEnv {}
}
}
Loading
Loading