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,179 changes: 929 additions & 1,250 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
"@types/write-file-atomic": "^4.0.3",
"@types/ws": "^8.18.1",
"@types/yauzl": "^2.10.3",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/coverage-v8": "^4.1.11",
"@vitest/eslint-plugin": "1.3.13",
"c8": "^10.1.3",
"cheerio": "^1.1.2",
Expand All @@ -196,7 +196,7 @@
"memfs": "^4.56.10",
"nock": "^14.0.10",
"npm-run-all2": "^8.0.4",
"oxfmt": "0.61.0",
"oxfmt": "0.72.0",
"p-timeout": "^7.0.0",
"picomatch": "^4.0.4",
"pkg-pr-new": "^0.0.86",
Expand All @@ -210,7 +210,7 @@
"typescript-eslint": "~8.65.0",
"typescript-native": "npm:typescript@~7.0.2",
"verdaccio": "^6.3.2",
"vitest": "^3.2.4"
"vitest": "^4.1.11"
},
"engines": {
"node": ">=22.13.0"
Expand Down
32 changes: 14 additions & 18 deletions src/commands/logs/sources/edge-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,27 @@ export const fetchEdgeFunctionHistoricalLogs = async ({
filterNames.map(async (filterName) => {
const baseUrl = buildEdgeFunctionLogsUrl({ siteId, search: filterName })
const entries = await fetchHistoricalLogs({ baseUrl, accessToken, from, to, deployId })
return entries.map(
(entry): LogEntry => ({
source: 'edge-function',
name: entry.name ?? entry.function ?? filterName,
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}),
)
return entries.map((entry): LogEntry => ({
source: 'edge-function',
name: entry.name ?? entry.function ?? filterName,
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}))
}),
)
return results.flat()
}

const baseUrl = buildEdgeFunctionLogsUrl({ siteId })
const entries = await fetchHistoricalLogs({ baseUrl, accessToken, from, to, deployId })
return entries.map(
(entry): LogEntry => ({
source: 'edge-function',
name: entry.name ?? entry.function ?? 'edge-function',
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}),
)
return entries.map((entry): LogEntry => ({
source: 'edge-function',
name: entry.name ?? entry.function ?? 'edge-function',
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}))
}

export const streamEdgeFunctions = (
Expand Down
16 changes: 7 additions & 9 deletions src/commands/logs/sources/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,13 @@ export const fetchFunctionHistoricalLogs = async ({
functions.map(async (fn) => {
const baseUrl = buildFunctionLogsUrl({ siteId, branch: fn.branch, functionName: fn.n })
const entries = await fetchHistoricalLogs({ baseUrl, accessToken, from, to, deployId })
return entries.map(
(entry): LogEntry => ({
source: 'function',
name: fn.n,
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}),
)
return entries.map((entry): LogEntry => ({
source: 'function',
name: fn.n,
ts: entry.ts,
level: entry.level || 'INFO',
message: entry.message,
}))
}),
)
return results.flat()
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/commands/blobs/blobs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('blobs:* commands', () => {
fixture.callCli(['blobs:get', 'my-store', 'my-key'], {
offline: false,
}),
).rejects.toThrowError('Error: Blob my-key does not exist in store my-store')
).rejects.toThrow('Error: Blob my-key does not exist in store my-store')
})

test<FixtureTestContext>('should send the region to the API when one is given', async ({ fixture }) => {
Expand Down Expand Up @@ -149,7 +149,7 @@ describe('blobs:* commands', () => {
fixture.callCli(['blobs:list', 'my-store', '--region', 'mars-north-1', '--json'], {
offline: false,
}),
).rejects.toThrowError('not a supported Netlify Blobs region')
).rejects.toThrow('not a supported Netlify Blobs region')
})
})
})
4 changes: 2 additions & 2 deletions tests/integration/commands/deploy/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ describe.concurrent('deploy command', () => {

const output: string = await callCli(['deploy', '--json'], getCLIOptions({ apiUrl: mockApi.apiUrl, builder }))

expect(() => JSON.parse(output)).not.toThrowError()
expect(() => JSON.parse(output)).not.toThrow()
})
})
})
Expand Down Expand Up @@ -805,7 +805,7 @@ describe.concurrent('deploy command', () => {
})

// stdout should still be valid JSON
expect(() => JSON.parse(stdout)).not.toThrowError()
expect(() => JSON.parse(stdout)).not.toThrow()

// stderr should contain the build output with line breaks preserved
expect(stderr).toContain('Build stdout line 1')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ describe.concurrent('commands/dev-forms-and-redirects', () => {
true,
),
)
.rejects.toThrowError()
.rejects.toThrow()
})
})
})
4 changes: 2 additions & 2 deletions tests/integration/commands/dev/dev-miscellaneous.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ describe.concurrent('commands/dev-miscellaneous', () => {
await withSiteBuilder(t, async (builder) => {
setupRoleBasedRedirectsSite(builder)
await builder.build()
await t.expect(validateRoleBasedRedirectsSite({ builder, t })).resolves.not.toThrowError()
await t.expect(validateRoleBasedRedirectsSite({ builder, t })).resolves.not.toThrow()
})
})

Expand All @@ -261,7 +261,7 @@ describe.concurrent('commands/dev-miscellaneous', () => {
},
})
await builder.build()
await t.expect(validateRoleBasedRedirectsSite({ builder, t, jwtSecret, jwtRolePath })).resolves.not.toThrowError()
await t.expect(validateRoleBasedRedirectsSite({ builder, t, jwtSecret, jwtRolePath })).resolves.not.toThrow()
})
})

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/commands/dev/dev.zisi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ export const handler = async function () {
`Expect: 100-continue' header`,
]),
)
.resolves.not.toThrowError()
.resolves.not.toThrow()
})
})
})
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/commands/env/env-set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ describe('env:set command', async () => {
offline: false,
parseJson: false,
}),
).rejects.toThrowError(`please specify a non-development context`)
).rejects.toThrow(`please specify a non-development context`)
})
test.concurrent<FixtureTestContext>('should error when set with a post-processing --scope', async ({
fixture,
Expand All @@ -257,7 +257,7 @@ describe('env:set command', async () => {
parseJson: false,
},
),
).rejects.toThrowError(`Secret values cannot be used within the post-processing scope.`)
).rejects.toThrow(`Secret values cannot be used within the post-processing scope.`)
})
test.concurrent<FixtureTestContext>('should error when --scope and --context are passed on an existing env var', async ({
fixture,
Expand All @@ -267,7 +267,7 @@ describe('env:set command', async () => {
offline: false,
parseJson: false,
}),
).rejects.toThrowError(`Setting the context and scope at the same time on an existing env var is not allowed`)
).rejects.toThrow(`Setting the context and scope at the same time on an existing env var is not allowed`)
})
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ describe.concurrent('functions:create command', async () => {

handleQuestions(childProcess, createFunctionQuestions)

await expect(childProcess).rejects.toThrowError('Invalid language: coffeescript')
await expect(childProcess).rejects.toThrow('Invalid language: coffeescript')

expect(await fileExistsAsync(`${builder.directory}/test/functions/hello-world/hello-world.mjs`)).toBe(false)
})
Expand Down Expand Up @@ -288,7 +288,7 @@ describe.concurrent('functions:create command', async () => {
},
])

await expect(childProcess).rejects.toThrowError('Invalid function name')
await expect(childProcess).rejects.toThrow('Invalid function name')

expect(existsSync(join(builder.directory, '..', 'evil'))).toBe(false)
})
Expand Down Expand Up @@ -320,7 +320,7 @@ describe.concurrent('functions:create command', async () => {
},
])

await expect(childProcess).rejects.toThrowError('Invalid function name')
await expect(childProcess).rejects.toThrow('Invalid function name')
})
})
})
Expand Down Expand Up @@ -348,7 +348,7 @@ describe.concurrent('functions:create command', async () => {
},
])

await expect(childProcess).rejects.toThrowError('Invalid function name')
await expect(childProcess).rejects.toThrow('Invalid function name')

expect(existsSync(join(builder.directory, '..', 'evil'))).toBe(false)
})
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/commands/sites/sites.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('sites command', () => {

await expect(async () => {
await program.parseAsync(['', '', 'sites:create', '--name', Array.from({ length: 64 }).fill('a').join('')])
}).rejects.toThrowError('--name should be less than 64 characters')
}).rejects.toThrow('--name should be less than 64 characters')
})
})

Expand Down Expand Up @@ -165,7 +165,7 @@ describe('sites command', () => {
'test-account',
'--disable-linking',
])
}).rejects.toThrowError(/already taken/)
}).rejects.toThrow(/already taken/)

const siteCreateRequests = requests.filter(
(r) => r.path === '/api/v1/test-account/sites' && r.method === 'POST',
Expand Down Expand Up @@ -224,7 +224,7 @@ describe('sites command', () => {
'test-account',
'--disable-linking',
])
}).rejects.toThrowError(/already taken/)
}).rejects.toThrow(/already taken/)

const siteCreateRequests = requests.filter(
(r) => r.path === '/api/v1/test-account/sites' && r.method === 'POST',
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/telemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ await withMockApi(routes, () => {
})

test<MockApiTestContext>('should send invoked command on failure', async ({ apiUrl, requests }) => {
await expect(callCli(['dev:exec', 'exit 1'], getCLIOptions(apiUrl))).rejects.toThrowError()
await expect(callCli(['dev:exec', 'exit 1'], getCLIOptions(apiUrl))).rejects.toThrow()
const request = requests.find(({ path }) => path === '/api/v1/track')
expect(request).toBeDefined()

Expand Down Expand Up @@ -136,7 +136,7 @@ await withMockApi(routes, () => {
}) => {
await expect(
callCli(['blobs:get', '--filter', 'web', '-O', './output_dir', 'my-store', 'my-key'], getCLIOptions(apiUrl)),
).rejects.toThrowError(/You don't appear to be in a folder that is linked to a project/)
).rejects.toThrow(/You don't appear to be in a folder that is linked to a project/)
const request = requests.find(({ path }) => path === '/api/v1/track')
expect(request).toBeDefined()

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/commands/api/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('apiCommand --data parsing', () => {
})

test('rejects key=value input with an error naming --data', async () => {
await expect(runApi('site_id=123')).rejects.toThrowError(/--data/)
await expect(runApi('site_id=123')).rejects.toThrow(/--data/)
expect(getSite).not.toHaveBeenCalled()
})

Expand Down
5 changes: 4 additions & 1 deletion tests/unit/commands/clone/clone.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ describe('clone command', () => {
beforeEach(() => {
vi.clearAllMocks()
mockLink.mockResolvedValue(undefined)
MockLocalState.mockImplementation((cwd: string) => ({ cwd }))
// vitest 4 constructs mocks called with `new`, so the implementation cannot be an arrow function.
MockLocalState.mockImplementation(function (cwd: string) {
return { cwd }
})
})

it('re-resolves repositoryRoot and state for the cloned directory before linking, instead of the pre-clone one', async () => {
Expand Down
19 changes: 11 additions & 8 deletions tests/unit/commands/login/login-check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ const mocks = vi.hoisted(() => ({
}))

vi.mock('@netlify/api', () => ({
NetlifyAPI: vi.fn().mockImplementation(() => ({
showTicket: mocks.showTicket,
exchangeTicket: mocks.exchangeTicket,
getCurrentUser: mocks.getCurrentUser,
set accessToken(_val: string) {
// no-op for test
},
})),
// vitest 4 constructs mocks called with `new`, so the implementation cannot be an arrow function.
NetlifyAPI: vi.fn(function () {
return {
showTicket: mocks.showTicket,
exchangeTicket: mocks.exchangeTicket,
getCurrentUser: mocks.getCurrentUser,
set accessToken(_val: string) {
// no-op for test
},
}
}),
}))

import type { GlobalConfigStore } from '@netlify/dev-utils'
Expand Down
7 changes: 4 additions & 3 deletions tests/unit/commands/login/login-request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ const mocks = vi.hoisted(() => ({
}))

vi.mock('@netlify/api', () => ({
NetlifyAPI: vi.fn().mockImplementation(() => ({
createTicket: mocks.createTicket,
})),
// vitest 4 constructs mocks called with `new`, so the implementation cannot be an arrow function.
NetlifyAPI: vi.fn(function () {
return { createTicket: mocks.createTicket }
}),
}))

import { loginRequest } from '../../../../src/commands/login/login-request.js'
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/lib/exec-fetcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,23 @@ describe('fetchLatestVersion', () => {
processPlatformSpy.mockReturnValue('win32')
vi.mocked(fetch).mockResolvedValue(new Response('Not Found', { status: 404 }))

await expect(fetchLatestVersion({ ...FETCH_ARGS, extension: 'zip' })).rejects.toThrowError(
await expect(fetchLatestVersion({ ...FETCH_ARGS, extension: 'zip' })).rejects.toThrow(
/The operating system windows with the CPU architecture amd64 is currently not supported!/,
)
})

test('throws the HTTP status on non-404 download errors', async () => {
vi.mocked(fetch).mockResolvedValue(new Response('Internal Server Error', { status: 500 }))

await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrowError(/Download failed: 500/)
await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrow(/Download failed: 500/)
})

test('includes the platform and arch in the 404 error for linux-x64', async () => {
processArchSpy.mockReturnValue('x64')
processPlatformSpy.mockReturnValue('linux')
vi.mocked(fetch).mockResolvedValue(new Response('Not Found', { status: 404 }))

await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrowError(
await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrow(
/The operating system linux with the CPU architecture amd64 is currently not supported!/,
)
})
Expand All @@ -98,7 +98,7 @@ describe('fetchLatestVersion', () => {
.mockResolvedValueOnce(new Response(JSON.stringify({ tag_name: 'v2.0.0' })))
.mockResolvedValueOnce(new Response('Not Found', { status: 404 }))

await expect(fetchLatestVersion({ ...FETCH_ARGS, latestVersion: undefined })).rejects.toThrowError()
await expect(fetchLatestVersion({ ...FETCH_ARGS, latestVersion: undefined })).rejects.toThrow()

expect(vi.mocked(fetch)).toHaveBeenCalledWith(
'https://api.github.com/repos/netlify/traffic-mesh-agent/releases/latest',
Expand All @@ -113,7 +113,7 @@ describe('fetchLatestVersion', () => {
test('throws when the GitHub releases API returns an error', async () => {
vi.mocked(fetch).mockResolvedValueOnce(new Response(null, { status: 403 }))

await expect(fetchLatestVersion({ ...FETCH_ARGS, latestVersion: undefined })).rejects.toThrowError(
await expect(fetchLatestVersion({ ...FETCH_ARGS, latestVersion: undefined })).rejects.toThrow(
/Failed to fetch latest release.*403/,
)
})
Expand Down Expand Up @@ -144,7 +144,7 @@ describe('fetchLatestVersion', () => {

vi.mocked(fetch).mockResolvedValue(new Response('error', { status: 500 }))

await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrowError()
await expect(fetchLatestVersion(FETCH_ARGS)).rejects.toThrow()

expect(vi.mocked(fetch)).toHaveBeenCalledWith(
expect.any(String),
Expand Down
Loading
Loading