console/integration-tests/testkit/cli.ts

183 lines
5 KiB
TypeScript

import { randomUUID } from 'node:crypto';
import { writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import 'jest-expect-message';
import { execaCommand } from '@esm2cjs/execa';
import { fetchLatestSchema, fetchLatestValidSchema } from './flow';
import { getServiceHost } from './utils';
const binPath = resolve(__dirname, '../../packages/libraries/cli/bin/run');
const cliDir = resolve(__dirname, '../../packages/libraries/cli');
async function generateTmpFile(content: string, extension: string) {
const dir = tmpdir();
const fileName = randomUUID();
const filepath = join(dir, `${fileName}.${extension}`);
await writeFile(filepath, content, 'utf-8');
return filepath;
}
export async function createCLI(token: string) {
let publishCount = 0;
async function publish({
sdl,
serviceName,
serviceUrl,
metadata,
expect: expectedStatus,
force,
acceptBreakingChanges,
}: {
sdl: string;
commit?: string;
serviceName?: string;
serviceUrl?: string;
metadata?: string;
force?: boolean;
acceptBreakingChanges?: boolean;
expect: 'latest' | 'latest-composable' | 'ignored' | 'rejected';
}) {
const publishName = ` #${++publishCount}`;
const commit = randomUUID();
const cmd = schemaPublish([
'--token',
token,
'--author',
'Kamil',
'--commit',
commit,
...(serviceName ? ['--service', serviceName] : []),
...(serviceUrl ? ['--url', serviceUrl] : []),
...(metadata ? ['--metadata', metadata] : []),
...(force ? ['--force'] : []),
...(acceptBreakingChanges ? ['--experimental_acceptBreakingChanges'] : []),
await generateTmpFile(sdl, 'graphql'),
]);
const expectedCommit = expect.objectContaining({
commit,
});
if (expectedStatus === 'rejected') {
await expect(cmd).rejects.toThrow();
const latestSchemaResult = await fetchLatestSchema(token).then(r =>
r.expectNoGraphQLErrors(),
);
const latestSchemaCommit = latestSchemaResult.latestVersion?.commit;
expect(
latestSchemaCommit,
`${publishName} was expected to be rejected but was published`,
).not.toEqual(expectedCommit);
return;
}
// throw if the command fails
try {
await cmd;
} catch (error) {
throw new Error(`${publishName} failed: ${String(error)}`);
}
const latestSchemaResult = await fetchLatestSchema(token).then(r => r.expectNoGraphQLErrors());
const latestSchemaCommit = latestSchemaResult.latestVersion?.commit;
if (expectedStatus === 'ignored') {
// Check if the schema was ignored
expect(
latestSchemaCommit,
`${publishName} was expected to be ignored but it was published`,
).not.toEqual(expectedCommit);
return;
}
// Check if the schema was published
expect(latestSchemaCommit, `${publishName} was expected to be published`).toEqual(
expectedCommit,
);
const latestComposableSchemaResult = await fetchLatestValidSchema(token).then(r =>
r.expectNoGraphQLErrors(),
);
const latestComposableSchemaCommit = latestComposableSchemaResult.latestValidVersion?.commit;
// Check if the schema was published as composable or non-composable
if (expectedStatus === 'latest') {
// schema is not available to the gateway
expect(
latestComposableSchemaCommit,
`${publishName} was expected to be published but not as composable`,
).not.toEqual(expectedCommit);
} else {
// schema is available to the gateway
expect(
latestComposableSchemaCommit,
`${publishName} was expected to be published as composable`,
).toEqual(expectedCommit);
}
}
async function check({
sdl,
serviceName,
expect: expectedStatus,
}: {
sdl: string;
serviceName?: string;
expect: 'approved' | 'rejected';
}) {
const cmd = schemaCheck([
'--token',
token,
...(serviceName ? ['--service', serviceName] : []),
await generateTmpFile(sdl, 'graphql'),
]);
if (expectedStatus === 'rejected') {
await expect(cmd).rejects.toThrow();
return cmd.catch(reason => Promise.resolve(reason.message));
}
return cmd;
}
return {
publish,
check,
};
}
async function exec(cmd: string) {
const outout = await execaCommand(`${binPath} ${cmd}`, {
shell: true,
env: {
OCLIF_CLI_CUSTOM_PATH: cliDir,
},
});
if (outout.failed) {
throw new Error(outout.stderr);
}
return outout.stdout;
}
export async function schemaPublish(args: string[]) {
const registryAddress = await getServiceHost('server', 8082);
return await exec(
['schema:publish', `--registry`, `http://${registryAddress}/graphql`, ...args].join(' '),
);
}
export async function schemaCheck(args: string[]) {
const registryAddress = await getServiceHost('server', 8082);
return await exec(
['schema:check', `--registry`, `http://${registryAddress}/graphql`, ...args].join(' '),
);
}