Skip to content

Commit

Permalink
feat: e2e test output now colored and interleaved
Browse files Browse the repository at this point in the history
  • Loading branch information
samjcombs committed Nov 14, 2024
1 parent 4d46443 commit f6ff071
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ frontend/build
deployToGCP.sh
certs
backend/data
backend/dist
backend/instant-mock.db
backend/src/migrations/**/*.snapshot*
minikube*
Expand Down
7 changes: 3 additions & 4 deletions backend/src/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {GET_VARIANT} from './queries/getVariant';
import {PROPOSAL_LAUNCHES} from './queries/proposalLaunches';
import {logger} from '../utilities/logger';
import {SchemaLoader} from '../utilities/schemaLoader';
import {printSchema} from 'graphql';

export default class Client {
private apolloClient!: ApolloClient<unknown>;
Expand Down Expand Up @@ -129,7 +128,7 @@ export default class Client {
const operationMatchArguments = operation.variables;
const seedResponse = response;

const apiUrl = `http://instant-mock-e2e-play:${process.env.PLAY_PORT}/api/seeds`;
const apiUrl = `http://localhost:${process.env.PLAY_PORT}/api/seeds`;

if (operationName === 'IntrospectionQuery') {
return response;
Expand Down Expand Up @@ -316,7 +315,7 @@ export default class Client {
latestPublication: {
publishedAt: new Date().toISOString(),
schema: {
document: printSchema(schema.schema),
document: schema.schema,
},
},
};
Expand Down Expand Up @@ -348,7 +347,7 @@ export default class Client {
latestPublication: {
publishedAt: new Date().toISOString(),
schema: {
document: printSchema(schema.schema),
document: schema.schema,
},
},
},
Expand Down
10 changes: 9 additions & 1 deletion backend/src/routes/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const mutex = new Mutex();
export const getOrStartNewMockServer = async (
graphId: string,
variantName: string
): Promise<MockServer> => {
): Promise<MockServer | undefined> => {
const release = await mutex.acquire();
try {
let mockInstance = mockInstances[graphId]?.[variantName];
Expand All @@ -25,6 +25,8 @@ export const getOrStartNewMockServer = async (
mockInstance = await startNewMockServer(graphId, variantName);
}
return mockInstance;
} catch (error) {
logger.error('Error getting or starting new mock server', {error});
} finally {
release();
}
Expand All @@ -37,6 +39,7 @@ const startNewMockServer = async (
logger.debug('Starting new mock server', {graphId, variantName});
const schema = await DI.apolloClient.getSchema(graphId, variantName);

if (!schema) throw new Error('Schema not found');
const mockServer = new MockServer(schema, {
subgraph: false,
fakerConfig: {},
Expand Down Expand Up @@ -103,6 +106,11 @@ const handleGraphQLRequest = async (
}

const mockServer = await getOrStartNewMockServer(graphId, variantName);
if (!mockServer) {
console.error('Could not start mock server', {graphId, variantName});
return res.status(422).json({message: 'Could not start mock server'});
}

const queryWithoutFragments = mockServer.expandFragments(query);
const typenamedQuery = mockServer.addTypenameFieldsToQuery(
queryWithoutFragments
Expand Down
4 changes: 4 additions & 0 deletions backend/src/routes/seeds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ router.post('/seeds', async (req: Request, res: Response) => {
logger.debug('Attempting to add a new seed', {graphId, variantName});

const mockServer = await getOrStartNewMockServer(graphId, variantName);
if (!mockServer) {
console.error('Could not start mock server', {graphId, variantName});
return res.status(422).json({message: 'Could not start mock server'});
}
const seedGroup = DI.em.getReference(SeedGroup, seedGroupId);

const seed = DI.seeds.create({
Expand Down
69 changes: 54 additions & 15 deletions scripts/run-e2e-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,44 @@ dotenv.config();

const FIXTURE_BASE_PATH = path.join("test", "e2e", "fixtures");

async function waitForServerReady(containerName: string): Promise<boolean> {
const colors = {
play: "\x1b[34m", // Blue for play server logs
record: "\x1b[35m", // Magenta for record server logs
test: "\x1b[36m", // Cyan for test server logs
cypress: "\x1b[32m", // Green for Cypress output
reset: "\x1b[0m", // Reset color
};

function addPrefixAndColor(prefix: string, color: string, message: string) {
const timestamp = format(new Date(), "yyyy-MM-dd HH:mm:ss");
return `${color}[${prefix} - ${timestamp}] ${message}${colors.reset}`;
}

async function waitForServerReady(
containerName: string,
color: string,
): Promise<boolean> {
return new Promise((resolve) => {
const logs = spawn("docker", ["logs", "-f", containerName]);
let serverReady = false;

logs.stdout.on("data", (data) => {
const output = data.toString();
console.log(output);
if (output.includes("Server running")) {
logs.kill();
console.log(addPrefixAndColor(containerName, color, output));
if (output.includes("Server running") && !serverReady) {
serverReady = true;
resolve(true);
}
});

logs.stderr.on("data", (data) => console.error(data.toString()));
logs.stderr.on("data", (data) => {
console.error(addPrefixAndColor(containerName, color, data.toString()));
});

setTimeout(() => {
logs.kill();
resolve(false);
if (!serverReady) {
resolve(false);
}
}, 30000);
});
}
Expand Down Expand Up @@ -80,41 +100,60 @@ function startDockerService(service: string, envVars: NodeJS.ProcessEnv) {
async function runTests(mode: string, timestamp: string) {
const baseEnvVars = { FIXTURE_TIMESTAMP: timestamp };

// Start the play server in both modes, with additional APOLLO_API_KEY in record mode
const playEnvVars =
mode === "record" && process.env.APOLLO_API_KEY
? { ...baseEnvVars, APOLLO_API_KEY: process.env.APOLLO_API_KEY }
: baseEnvVars;

startDockerService("instant-mock-e2e-play", playEnvVars);
const playHealthy = await waitForServerReady("instant-mock-e2e-play");
const playHealthy = await waitForServerReady(
"instant-mock-e2e-play",
colors.play,
);
if (!playHealthy) {
throw new Error("Play server failed to start properly");
}

// Additional setup for 'record' and 'test' modes
if (mode === "record") {
startDockerService("instant-mock-e2e-record", baseEnvVars);
const recordHealthy = await waitForServerReady("instant-mock-e2e-record");
const recordHealthy = await waitForServerReady(
"instant-mock-e2e-record",
colors.record,
);
if (!recordHealthy) {
throw new Error("Record server failed to start properly");
}
} else if (mode === "test") {
startDockerService("instant-mock-e2e-test", baseEnvVars);
const testHealthy = await waitForServerReady("instant-mock-e2e-test");
const testHealthy = await waitForServerReady(
"instant-mock-e2e-test",
colors.test,
);
if (!testHealthy) {
throw new Error("Test server failed to start properly");
}
}

// Determine Cypress base URL based on mode
const baseUrl =
mode === "record" ? process.env.RECORD_PORT : process.env.TEST_PORT;
console.log(`Running Cypress tests against port ${baseUrl}...`);
execSync(

const cypressOutput = spawn(
`CYPRESS_BASE_URL=http://localhost:${baseUrl} npx cypress run --spec 'cypress/e2e/basic-functionality.cy.ts'`,
{ stdio: "inherit", env: { ...process.env, ...baseEnvVars } },
{ shell: true, env: { ...process.env, ...baseEnvVars } },
);

cypressOutput.stdout.on("data", (data) => {
console.log(addPrefixAndColor("Cypress", colors.cypress, data.toString()));
});

cypressOutput.stderr.on("data", (data) => {
console.error(
addPrefixAndColor("Cypress", colors.cypress, data.toString()),
);
});

await new Promise((resolve) => cypressOutput.on("close", resolve));
}

function shutdownDocker() {
Expand Down

0 comments on commit f6ff071

Please sign in to comment.