Skip to content

Commit 0b2eb5a

Browse files
committed
fix: make command metadata specs side effect free
1 parent ecf83e1 commit 0b2eb5a

5 files changed

Lines changed: 41 additions & 73 deletions

File tree

tests/unit/commands/create_tenant.spec.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
import { test } from '@japa/runner'
22
import { readFile } from 'node:fs/promises'
3-
import CreateTenant from '../../../src/commands/create_tenant.js'
43

4+
/**
5+
* Metadata-only spec. We intentionally do NOT import
6+
* `src/commands/create_tenant.ts`: its module graph reaches
7+
* `jobs/install_tenant.ts`, which eagerly imports
8+
* `@adonisjs/core/services/logger`. That logger module top-level
9+
* `await`s `app.booted(...)`, which throws when evaluated outside an
10+
* Ignitor (i.e. the unit suite). Reading the same contract from
11+
* `commands.json` + the barrel keeps the assertion meaningful while
12+
* staying side-effect-free.
13+
*/
514
test.group('tenant:create — command metadata', () => {
6-
test('exports a command with the canonical name', ({ assert }) => {
7-
assert.equal(CreateTenant.commandName, 'tenant:create')
8-
})
9-
10-
test('description names the contract clearly', ({ assert }) => {
11-
assert.match(CreateTenant.description, /create a new tenant/i)
12-
})
13-
14-
test('starts the app (needs the container booted to resolve the repo)', ({ assert }) => {
15-
assert.equal(CreateTenant.options?.startApp, true)
16-
})
17-
18-
test('is registered in commands.json with name + email args', async ({ assert }) => {
15+
test('is registered in commands.json with the canonical contract', async ({ assert }) => {
1916
const json = JSON.parse(
2017
await readFile(new URL('../../../src/commands/commands.json', import.meta.url), 'utf-8')
2118
)
2219
const entry = json.commands.find((c: any) => c.commandName === 'tenant:create')
2320
assert.exists(entry, 'tenant:create missing from commands.json')
2421
assert.equal(entry.filePath, 'create_tenant.js')
22+
assert.match(entry.description, /create a new tenant/i)
23+
assert.equal(entry.options?.startApp, true, 'must start the app to resolve the repo')
2524

2625
const argNames = entry.args.map((a: any) => a.argumentName)
2726
assert.deepEqual(argNames, ['name', 'email'])

tests/unit/commands/destroy_tenant.spec.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
11
import { test } from '@japa/runner'
22
import { readFile } from 'node:fs/promises'
3-
import DestroyTenant from '../../../src/commands/destroy_tenant.js'
43

4+
/**
5+
* Metadata-only spec — see `create_tenant.spec.ts` for the rationale
6+
* behind not importing the command module here. We assert the same
7+
* contract through `commands.json` + the barrel.
8+
*/
59
test.group('tenant:destroy — command metadata', () => {
6-
test('exports a command with the canonical name', ({ assert }) => {
7-
assert.equal(DestroyTenant.commandName, 'tenant:destroy')
8-
})
9-
10-
test('description names the contract clearly', ({ assert }) => {
11-
assert.match(DestroyTenant.description, /soft-delete.*tear down/i)
12-
})
13-
14-
test('starts the app (lifecycle hooks + driver need the container)', ({ assert }) => {
15-
assert.equal(DestroyTenant.options?.startApp, true)
16-
})
17-
18-
test('is registered in commands.json with --force and --keep-schema flags', async ({
19-
assert,
20-
}) => {
10+
test('is registered in commands.json with the canonical contract', async ({ assert }) => {
2111
const json = JSON.parse(
2212
await readFile(new URL('../../../src/commands/commands.json', import.meta.url), 'utf-8')
2313
)
2414
const entry = json.commands.find((c: any) => c.commandName === 'tenant:destroy')
2515
assert.exists(entry, 'tenant:destroy missing from commands.json')
2616
assert.equal(entry.filePath, 'destroy_tenant.js')
17+
assert.match(entry.description, /soft-delete.*tear down/i)
18+
assert.equal(entry.options?.startApp, true)
2719

2820
const flagNames = entry.flags.map((f: any) => f.flagName).sort()
2921
assert.deepEqual(flagNames, ['force', 'keep-schema'])

tests/unit/commands/tenant_backup.spec.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
import { test } from '@japa/runner'
22
import { readFile } from 'node:fs/promises'
3-
import TenantBackup from '../../../src/commands/tenant_backup.js'
43

4+
/**
5+
* Metadata-only spec — see `create_tenant.spec.ts` for the rationale
6+
* behind not importing the command module here.
7+
*/
58
test.group('tenant:backup — command metadata', () => {
6-
test('exports a command with the canonical name', ({ assert }) => {
7-
assert.equal(TenantBackup.commandName, 'tenant:backup')
8-
})
9-
10-
test('description names the contract clearly', ({ assert }) => {
11-
assert.match(TenantBackup.description, /backup.*tenant/i)
12-
})
13-
14-
test('starts the app (BackupService reads runtime config)', ({ assert }) => {
15-
assert.equal(TenantBackup.options?.startApp, true)
16-
})
17-
18-
test('is registered in commands.json with the --tenant filter flag', async ({ assert }) => {
9+
test('is registered in commands.json with the canonical contract', async ({ assert }) => {
1910
const json = JSON.parse(
2011
await readFile(new URL('../../../src/commands/commands.json', import.meta.url), 'utf-8')
2112
)
2213
const entry = json.commands.find((c: any) => c.commandName === 'tenant:backup')
2314
assert.exists(entry, 'tenant:backup missing from commands.json')
2415
assert.equal(entry.filePath, 'tenant_backup.js')
16+
assert.match(entry.description, /backup.*tenant/i)
17+
assert.equal(entry.options?.startApp, true)
2518

2619
const flagNames = entry.flags.map((f: any) => f.flagName).sort()
2720
assert.deepEqual(flagNames, ['tenant'])

tests/unit/commands/tenant_doctor.spec.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
import { test } from '@japa/runner'
22
import { readFile } from 'node:fs/promises'
3-
import TenantDoctor from '../../../src/commands/tenant_doctor.js'
43

4+
/**
5+
* Metadata-only spec — see `create_tenant.spec.ts` for the rationale
6+
* behind not importing the command module here.
7+
*/
58
test.group('tenant:doctor — command metadata', () => {
6-
test('exports a command with the canonical name', ({ assert }) => {
7-
assert.equal(TenantDoctor.commandName, 'tenant:doctor')
8-
})
9-
10-
test('description names the contract clearly', ({ assert }) => {
11-
assert.match(TenantDoctor.description, /diagnose tenancy state/i)
12-
})
13-
14-
test('starts the app (DoctorService and checks need the container booted)', ({ assert }) => {
15-
assert.equal(TenantDoctor.options?.startApp, true)
16-
})
17-
189
test('is registered in commands.json with the full operator surface', async ({ assert }) => {
1910
const json = JSON.parse(
2011
await readFile(new URL('../../../src/commands/commands.json', import.meta.url), 'utf-8')
2112
)
2213
const entry = json.commands.find((c: any) => c.commandName === 'tenant:doctor')
2314
assert.exists(entry, 'tenant:doctor missing from commands.json')
2415
assert.equal(entry.filePath, 'tenant_doctor.js')
16+
assert.match(entry.description, /diagnose tenancy state/i)
17+
assert.equal(entry.options?.startApp, true)
2518

2619
const flagNames = entry.flags.map((f: any) => f.flagName).sort()
2720
assert.deepEqual(flagNames, ['check', 'fix', 'interval', 'json', 'tenant', 'watch'])

tests/unit/commands/tenant_restore.spec.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,20 @@
11
import { test } from '@japa/runner'
22
import { readFile } from 'node:fs/promises'
3-
import TenantRestore from '../../../src/commands/tenant_restore.js'
43

4+
/**
5+
* Metadata-only spec — see `create_tenant.spec.ts` for the rationale
6+
* behind not importing the command module here.
7+
*/
58
test.group('tenant:restore — command metadata', () => {
6-
test('exports a command with the canonical name', ({ assert }) => {
7-
assert.equal(TenantRestore.commandName, 'tenant:restore')
8-
})
9-
10-
test('description names the contract clearly', ({ assert }) => {
11-
assert.match(TenantRestore.description, /restore.*backup/i)
12-
})
13-
14-
test('starts the app (BackupService reads runtime config)', ({ assert }) => {
15-
assert.equal(TenantRestore.options?.startApp, true)
16-
})
17-
18-
test('is registered in commands.json with --tenant + --file required flags', async ({
19-
assert,
20-
}) => {
9+
test('is registered in commands.json with the canonical contract', async ({ assert }) => {
2110
const json = JSON.parse(
2211
await readFile(new URL('../../../src/commands/commands.json', import.meta.url), 'utf-8')
2312
)
2413
const entry = json.commands.find((c: any) => c.commandName === 'tenant:restore')
2514
assert.exists(entry, 'tenant:restore missing from commands.json')
2615
assert.equal(entry.filePath, 'tenant_restore.js')
16+
assert.match(entry.description, /restore.*backup/i)
17+
assert.equal(entry.options?.startApp, true)
2718

2819
const flagNames = entry.flags.map((f: any) => f.flagName).sort()
2920
assert.deepEqual(flagNames, ['file', 'tenant'])

0 commit comments

Comments
 (0)