Skip to content
Closed
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"start": "node ./bin/run.js",
"test": "run-s test:unit test:integration test:e2e",
"test:e2e": "vitest run --config vitest.e2e.config.ts",
"test:init": "run-s test:init:*",
"test:init": "run-p test:init:*",
"test:init:cli-help": "npm run start -- --help",
"test:init:cli-version": "npm run start -- --version",
"test:init:hugo-deps": "npm ci --prefix tests/integration/__fixtures__/hugo-site --no-audit",
Expand Down
58 changes: 31 additions & 27 deletions tests/integration/commands/clone/clone.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { sep } from 'node:path'

import { describe, expect, it, beforeEach } from 'vitest'
import { describe, expect, it } from 'vitest'
import js from 'dedent'
import stripAnsi from 'strip-ansi'

Expand All @@ -11,33 +11,29 @@ import { createMock } from '../../utils/mock-execa.js'
import execa from 'execa'
import { cliPath } from '../../utils/cli-path.js'

describe.concurrent('clone command', () => {
let execaMock: Awaited<ReturnType<typeof createMock>>[0]

beforeEach(async () => {
;[execaMock] = await createMock(js`
module.exports = function execa(command, args) {
// Mock git clone command
if (command === 'git' && args[0] === 'clone') {
const targetDir = args[2]
return require('fs/promises').mkdir(targetDir, { recursive: true })
.then(() => {
const stdout = 'Mocked git clone received: ' + command + ' ' + args.join(' ')
console.log(stdout)
return { stdout, stderr: '' }
})
}
// For any other command, use the real execa
// Normalize paths for Windows
const realExeca = require('${require.resolve('execa').split(sep).join('/')}')
// execa's APi is... really weird
const result = Promise.resolve(realExeca(command, args))
result.unref = () => {}
return result
}
`)
})
const EXECA_MOCK_SOURCE = js`
module.exports = function execa(command, args) {
// Mock git clone command
if (command === 'git' && args[0] === 'clone') {
const targetDir = args[2]
return require('fs/promises').mkdir(targetDir, { recursive: true })
.then(() => {
const stdout = 'Mocked git clone received: ' + command + ' ' + args.join(' ')
console.log(stdout)
return { stdout, stderr: '' }
})
}
// For any other command, use the real execa
// Normalize paths for Windows
const realExeca = require('${require.resolve('execa').split(sep).join('/')}')
// execa's APi is... really weird
const result = Promise.resolve(realExeca(command, args))
result.unref = () => {}
return result
}
`

describe.concurrent('clone command', () => {
const SITE_INFO_FIXTURE = {
id: 'site_id',
name: 'test-site',
Expand Down Expand Up @@ -68,6 +64,7 @@ describe.concurrent('clone command', () => {
it.todo('prints an error and exits if not authenticated')

it("clones a repo and links it to the one project connected to that repo's HTTPS URL", async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const routes = [...API_ROUTES_FIXTURE]
const questions = [
{
Expand Down Expand Up @@ -132,6 +129,7 @@ To unlink this project, run: netlify unlink`)
})

it('clones into the provided `[targetDir]` if arg is provided', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const routes = [...API_ROUTES_FIXTURE]
const questions: never[] = [] // no interactive prompts at all

Expand Down Expand Up @@ -185,6 +183,7 @@ To unlink this project, run: netlify unlink`)
})

it('clones into the entered target dir if user enters one when prompted', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const routes = [...API_ROUTES_FIXTURE]
const questions = [
{
Expand Down Expand Up @@ -249,6 +248,7 @@ To unlink this project, run: netlify unlink`)
})

it('links to project with given `--id` when provided', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const otherSiteInfo = {
id: 'other-site-id',
name: 'other-site',
Expand Down Expand Up @@ -306,6 +306,7 @@ To unlink this project, run: netlify unlink`)
})

it('links to project with given `--name` when provided', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const otherSiteInfo = {
id: 'other-site-id',
name: 'other-site',
Expand Down Expand Up @@ -367,6 +368,7 @@ To unlink this project, run: netlify unlink`)
})

it('prompts user when multiple projects match git repo HTTPS URL', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const otherSiteInfo = {
id: 'other-site-id',
name: 'other-site',
Expand Down Expand Up @@ -425,6 +427,7 @@ To unlink this project, run: netlify unlink`)
})

it('prints an error and exits when no project is connected to the git repo HTTPS URL', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const otherSiteInfo = {
id: 'other-site-id',
name: 'other-site',
Expand Down Expand Up @@ -485,6 +488,7 @@ Run git remote -v to see a list of your git remotes.`)
})

it('prints an error and exits given an invalid git repo specifier', async (t) => {
const [execaMock] = await createMock(EXECA_MOCK_SOURCE)
const routes = [
{
path: 'sites',
Expand Down
16 changes: 16 additions & 0 deletions tests/integration/sequencer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BaseSequencer, type TestSpecification } from 'vitest/node'

/**
* Round-robin sharding so slow files (e.g. all `dev/*` tests) don't cluster in
* the same shard like they do under vitest's default sha1-hash distribution.
*/
export class BalancedShardSequencer extends BaseSequencer {
shard(files: TestSpecification[]): Promise<TestSpecification[]> {
const shardCfg = this.ctx.config.shard
if (!shardCfg) return Promise.resolve(files)

const sorted = [...files].sort((a, b) => a.moduleId.localeCompare(b.moduleId))
const mine = sorted.filter((_, i) => i % shardCfg.count === shardCfg.index - 1)
return Promise.resolve(mine)
}
}
5 changes: 5 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { defineConfig } from 'vitest/config'

import { BalancedShardSequencer } from './tests/integration/sequencer.js'

export default defineConfig({
test: {
include: ['tests/**/*.test.js', 'tests/**/*.test.ts'],
Expand All @@ -25,6 +27,9 @@ export default defineConfig({
singleThread: true,
},
},
sequence: {
sequencer: BalancedShardSequencer,
},
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
Expand Down
Loading