Skip to content

Commit

Permalink
Remove usage of getDbSchemaName, getPrismaPath, migrationMode and dro…
Browse files Browse the repository at this point in the history
…pDatabase from tests (#5276)

* Remove usage of getDbSchemaName, getPrismaPath and migrationMode from tests

* Fix things

* Fix things

* Try a thing

* Try things

* Try a thing

* Try a thing

* WIP

* WIP

* WIP

* Fix it

* Revert some changes and add some changesets
  • Loading branch information
emmatown authored Mar 30, 2021
1 parent 3928d2c commit 1a4db6c
Show file tree
Hide file tree
Showing 14 changed files with 86 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-news-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-next/test-utils-legacy': major
---

Removed usage of `getDbSchemaName`, `getPrismaPath`, `migrationMode` and `dropDatabase` adapter options. Note this means that dropping the database and running migrations will now only happen when creating a keystone instance from `setupFromConfig` rather than on every `keystone.connect`
5 changes: 5 additions & 0 deletions .changeset/happy-mugs-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-next/keystone': minor
---

Added `artifacts` entrypoint.
4 changes: 4 additions & 0 deletions packages-next/keystone/artifacts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "dist/keystone.cjs.js",
"module": "dist/keystone.esm.js"
}
1 change: 1 addition & 0 deletions packages-next/keystone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"preconstruct": {
"entrypoints": [
"index.ts",
"artifacts.ts",
"schema/index.ts",
"session/index.ts",
"scripts/index.ts"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { printSchema, GraphQLSchema } from 'graphql';
import * as fs from 'fs-extra';
import type { BaseKeystone } from '@keystone-next/types';
import { getGenerator } from '@prisma/sdk';
import { confirmPrompt } from './prompts';
import { printGeneratedTypes } from './schema-type-printer';
import { confirmPrompt } from './lib/prompts';
import { printGeneratedTypes } from './lib/schema-type-printer';

export function getSchemaPaths(cwd: string) {
return {
Expand Down
2 changes: 1 addition & 1 deletion packages-next/keystone/src/scripts/build/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AdminFileToWrite } from '@keystone-next/types';
import { createSystem } from '../../lib/createSystem';
import { initConfig } from '../../lib/initConfig';
import { requireSource } from '../../lib/requireSource';
import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../../lib/artifacts';
import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../../artifacts';
import { CONFIG_PATH, getAdminPath } from '../utils';

// FIXME: Duplicated from admin-ui package. Need to decide on a common home.
Expand Down
2 changes: 1 addition & 1 deletion packages-next/keystone/src/scripts/postinstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
generateCommittedArtifacts,
generateNodeModulesArtifacts,
validateCommittedArtifacts,
} from '../lib/artifacts';
} from '../artifacts';
import { requireSource } from '../lib/requireSource';
import { initConfig } from '../lib/initConfig';
import { CONFIG_PATH } from './utils';
Expand Down
2 changes: 1 addition & 1 deletion packages-next/keystone/src/scripts/prisma.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import execa from 'execa';
import { createSystem } from '../lib/createSystem';
import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../lib/artifacts';
import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../artifacts';
import { requireSource } from '../lib/requireSource';
import { initConfig } from '../lib/initConfig';
import { CONFIG_PATH } from './utils';
Expand Down
2 changes: 1 addition & 1 deletion packages-next/keystone/src/scripts/run/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
generateNodeModulesArtifacts,
getSchemaPaths,
requirePrismaClient,
} from '../../lib/artifacts';
} from '../../artifacts';
import { CONFIG_PATH, getAdminPath } from '../utils';

// TODO: Don't generate or start an Admin UI if it isn't configured!!
Expand Down
2 changes: 1 addition & 1 deletion packages-next/keystone/src/scripts/run/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createSystem } from '../../lib/createSystem';
import { initConfig } from '../../lib/initConfig';
import { createExpressServer } from '../../lib/createExpressServer';
import { getAdminPath } from '../utils';
import { requirePrismaClient } from '../../lib/artifacts';
import { requirePrismaClient } from '../../artifacts';

export const start = async (cwd: string) => {
console.log('✨ Starting Keystone');
Expand Down
18 changes: 13 additions & 5 deletions packages/adapter-prisma/src/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,27 @@ async function withMigrate<T>(
}
}

export async function runPrototypeMigrations(dbUrl: string, schema: string, schemaPath: string) {
export async function runPrototypeMigrations(
dbUrl: string,
schema: string,
schemaPath: string,
shouldDropDatabase = false
) {
let before = Date.now();

let migration = await withMigrate(dbUrl, schemaPath, async migrate =>
runMigrateWithDbUrl(dbUrl, () =>
let migration = await withMigrate(dbUrl, schemaPath, async migrate => {
if (shouldDropDatabase) {
await runMigrateWithDbUrl(dbUrl, () => migrate.engine.reset());
}
return runMigrateWithDbUrl(dbUrl, () =>
migrate.engine.schemaPush({
// TODO: we probably want to do something like db push does where either there's
// a prompt or an argument needs to be passed to make it force(i.e. lose data)
force: true,
schema,
})
)
);
);
});

if (migration.warnings.length === 0 && migration.executedSteps === 0) {
console.info(`✨ The database is already in sync with the Prisma schema.`);
Expand Down
1 change: 1 addition & 0 deletions packages/test-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"node": ">=10.0.0"
},
"dependencies": {
"@keystone-next/adapter-prisma-legacy": "^4.0.1",
"@keystone-next/keystone": "14.0.1",
"@keystone-next/keystone-legacy": "^22.0.0",
"express": "^4.17.1",
Expand Down
71 changes: 49 additions & 22 deletions packages/test-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import path from 'path';
import crypto from 'crypto';
import { ServerResponse } from 'http';
import fs from 'fs';
import express from 'express';
// @ts-ignore
import supertest from 'supertest-light';
// @ts-ignore
import { Keystone } from '@keystone-next/keystone-legacy';
import { initConfig, createSystem, createExpressServer } from '@keystone-next/keystone';
import { runPrototypeMigrations } from '@keystone-next/adapter-prisma-legacy';
import {
getCommittedArtifacts,
writeCommittedArtifacts,
requirePrismaClient,
generateNodeModulesArtifacts,
} from '@keystone-next/keystone/artifacts';
import type { KeystoneConfig, BaseKeystone, KeystoneContext } from '@keystone-next/types';
import memoizeOne from 'memoize-one';

Expand All @@ -18,27 +26,17 @@ const hashPrismaSchema = memoizeOne(prismaSchema =>

const argGenerator = {
prisma_postgresql: () => ({
migrationMode: 'prototype',
dropDatabase: true,
url: process.env.DATABASE_URL || '',
migrationMode: 'none-skip-client-generation',
url: process.env.DATABASE_URL!,
provider: 'postgresql',
// Put the generated client at a unique path
getPrismaPath: ({ prismaSchema }: { prismaSchema: string }) =>
path.join('.api-test-prisma-clients', hashPrismaSchema(prismaSchema)),
// Slice down to the hash make a valid postgres schema name
getDbSchemaName: ({ prismaSchema }: { prismaSchema: string }) =>
hashPrismaSchema(prismaSchema).slice(0, 16),
getDbSchemaName: () => null as any,
// Turn this on if you need verbose debug info
enableLogging: false,
}),
prisma_sqlite: () => ({
migrationMode: 'prototype',
dropDatabase: true,
url: process.env.DATABASE_URL || '',
migrationMode: 'none-skip-client-generation',
url: process.env.DATABASE_URL!,
provider: 'sqlite',
// Put the generated client at a unique path
getPrismaPath: ({ prismaSchema }: { prismaSchema: string }) =>
path.join('.api-test-prisma-clients', hashPrismaSchema(prismaSchema)),
// Turn this on if you need verbose debug info
enableLogging: false,
}),
Expand All @@ -50,9 +48,11 @@ const argGenerator = {
type TestKeystoneConfig = Omit<KeystoneConfig, 'db' | 'ui'>;
export const testConfig = (config: TestKeystoneConfig) => config;

const alreadyGeneratedProjects = new Set<string>();

async function setupFromConfig({
adapterName,
config,
config: _config,
}: {
adapterName: AdapterName;
config: TestKeystoneConfig;
Expand All @@ -64,13 +64,41 @@ async function setupFromConfig({
} else if (adapterName === 'prisma_sqlite') {
const adapterArgs = await argGenerator[adapterName]();
db = { adapter: adapterName, ...adapterArgs };
config.experimental = { prismaSqlite: true };
_config = { ..._config, experimental: { prismaSqlite: true } };
}
const _config = initConfig({ ...config, db: db!, ui: { isDisabled: true } });

const { keystone, createContext, graphQLSchema } = createSystem(_config, 'dev');

const app = await createExpressServer(_config, graphQLSchema, createContext, true, '', false);
const config = initConfig({ ..._config, db: db!, ui: { isDisabled: true } });

const prismaClient = await (async () => {
const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation');
const artifacts = await getCommittedArtifacts(graphQLSchema, keystone);
const hash = hashPrismaSchema(artifacts.prisma);
if (adapterName === 'prisma_postgresql') {
config.db.url = `${config.db.url}?schema=${hash.toString()}`;
}
const cwd = path.resolve('.api-test-prisma-clients', hash);
if (!alreadyGeneratedProjects.has(hash)) {
alreadyGeneratedProjects.add(hash);
fs.mkdirSync(cwd, { recursive: true });
await writeCommittedArtifacts(artifacts, cwd);
await generateNodeModulesArtifacts(graphQLSchema, keystone, cwd);
}
await runPrototypeMigrations(
config.db.url,
artifacts.prisma,
path.join(cwd, 'schema.prisma'),
true
);
return requirePrismaClient(cwd);
})();

const { keystone, createContext, graphQLSchema } = createSystem(
config,
'none-skip-client-generation',
prismaClient
);

const app = await createExpressServer(config, graphQLSchema, createContext, true, '', false);

return { keystone, context: createContext().sudo(), app };
}
Expand Down Expand Up @@ -126,7 +154,6 @@ function _keystoneRunner(adapterName: AdapterName, tearDownFunction: () => Promi
}
const setup = await setupKeystoneFn(adapterName);
const { keystone } = setup;

await keystone.connect();

try {
Expand Down
8 changes: 1 addition & 7 deletions tests/api-tests/fields/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import path from 'path';
import globby from 'globby';
import { multiAdapterRunners, setupFromConfig, testConfig } from '@keystone-next/test-utils-legacy';
import { createItem, getItems } from '@keystone-next/server-side-graphql-client-legacy';
import memoizeOne from 'memoize-one';
import { createSchema, list } from '@keystone-next/keystone/schema';
import { KeystoneContext } from '@keystone-next/types';

Expand All @@ -23,10 +22,7 @@ multiAdapterRunners().map(({ runner, adapterName }) =>
(mod.testMatrix || ['default']).forEach((matrixValue: string) => {
const listKey = 'Test';

// we want to memoize the server creation since it's the same fields
// for all the tests and setting up a keystone instance for prisma
// can be a bit slow
const _getServer = () =>
const getServer = () =>
setupFromConfig({
adapterName,
config: testConfig({
Expand All @@ -36,8 +32,6 @@ multiAdapterRunners().map(({ runner, adapterName }) =>
}),
});

const getServer = memoizeOne(_getServer);

const withKeystone = (testFn: (args: any) => void = () => {}) =>
runner(getServer, async ({ context, ...rest }) => {
// Populate the database before running the tests
Expand Down

1 comment on commit 1a4db6c

@vercel
Copy link

@vercel vercel bot commented on 1a4db6c Mar 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.