Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanoverna committed Jan 25, 2024
1 parent e52efdf commit ab51c7e
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 35 deletions.
3 changes: 3 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DATOCMS_ACCOUNT_EMAIL=""
DATOCMS_ACCOUNT_PASSWORD=""
DATOCMS_ORGANIZATION_ID=""
4 changes: 4 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ jobs:
- run: ./node_modules/.bin/lerna bootstrap
- run: npm run build --if-present
- run: npm test
env:
DATOCMS_ACCOUNT_EMAIL: ${{ secrets.DATOCMS_ACCOUNT_EMAIL }}
DATOCMS_ACCOUNT_PASSWORD: ${{ secrets.DATOCMS_ACCOUNT_PASSWORD }}
DATOCMS_ORGANIZATION_ID: ${{ secrets.DATOCMS_ORGANIZATION_ID }}
9 changes: 6 additions & 3 deletions jest-helpers/generateNewCmaClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { buildClient, ClientConfigOptions } from '../packages/cma-client-node';

import { fetch as ponyfillFetch } from '@whatwg-node/fetch';
import { buildClient, ClientConfigOptions } from '../packages/cma-client-node';
import { generateNewDashboardClient } from './generateNewDashboardClient';

const fetchFn = typeof fetch === 'undefined' ? ponyfillFetch : fetch;
Expand All @@ -15,12 +14,16 @@ export async function generateNewCmaClient(
) {
const dashboardClient = await generateNewDashboardClient();

const randomString =
Math.random().toString(36).substring(7) + new Date().getTime();

const site = await dashboardClient.sites.create({
name: 'Project',
name: `Project ${randomString}`,
});

return buildClient({
...extraConfig,
// biome-ignore lint/style/noNonNullAssertion: We're owners of the site, so readwrite_token is present
apiToken: site.readwrite_token!,
...baseConfigOptions,
});
Expand Down
100 changes: 77 additions & 23 deletions jest-helpers/generateNewDashboardClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { buildClient, ClientConfigOptions } from '../packages/dashboard-client';

import { fetch as ponyfillFetch } from '@whatwg-node/fetch';
import {
ApiError,
buildClient,
Client,
ClientConfigOptions,
} from '../packages/dashboard-client';

const fetchFn = typeof fetch === 'undefined' ? ponyfillFetch : fetch;

Expand All @@ -9,27 +13,77 @@ export const baseConfigOptions: Partial<ClientConfigOptions> = {
fetchFn,
};

function shuffleArray<T>(source: T[]) {
const array = [...source];

for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}

export async function generateNewDashboardClient(
extraConfig?: Partial<ClientConfigOptions>,
) {
const randomString =
Math.random().toString(36).substring(7) + new Date().getTime();

const client = buildClient({
apiToken: null,
...baseConfigOptions,
});

const account = await client.account.create({
email: `${randomString}@delete-this-at-midnight-utc.tk`,
password: 'STRONG_pass123!',
first_name: 'Test',
company: 'DatoCMS',
});

return buildClient({
...extraConfig,
apiToken: account.id,
...baseConfigOptions,
});
): Promise<Client> {
if (process.env.DATOCMS_SESSION_ID) {
return buildClient({
...extraConfig,
apiToken: process.env.DATOCMS_SESSION_ID,
organization: process.env.DATOCMS_ORGANIZATION_ID,
...baseConfigOptions,
});
}

if (
!process.env.DATOCMS_ACCOUNT_EMAIL ||
!process.env.DATOCMS_ACCOUNT_PASSWORD
) {
throw new Error(
'DATOCMS_ACCOUNT_EMAIL, DATOCMS_ACCOUNT_PASSWORD (and optionally DATOCMS_ORGANIZATION_ID) environment variables must be set on .env file!',
);
}

// To avoid incurring in rate limits, a pool of accouts that share the same
// password and organization membership can be used.

const emails = shuffleArray(
process.env.DATOCMS_ACCOUNT_EMAIL.split(/\s*,\s*/),
);

for (const email of emails) {
const client = buildClient({
...extraConfig,
apiToken: null,
autoRetry: false,
...baseConfigOptions,
});

try {
const account = await client.session.rawCreate({
data: {
type: 'email_credentials',
attributes: {
email: email,
password: process.env.DATOCMS_ACCOUNT_PASSWORD,
},
},
});

process.env.DATOCMS_SESSION_ID = account.data.id;

return generateNewDashboardClient(extraConfig);
} catch (e) {
// Let's try with next account
if (e instanceof ApiError && e.findError('RATE_LIMIT_EXCEEDED')) {
continue;
}

throw e;
}
}

throw new Error('Account pool exhausted!');
}
45 changes: 45 additions & 0 deletions jest-helpers/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'dotenv/config';
import { ApiError } from '../packages/dashboard-client';
import { generateNewDashboardClient } from './generateNewDashboardClient';

function isOldEnough(isoDatetime: string) {
const datetime = new Date(isoDatetime);

const oneDayAgo = new Date();
oneDayAgo.setDate(oneDayAgo.getDate() - 1);

return datetime < oneDayAgo;
}

export default async () => {
const client = await generateNewDashboardClient();

// Context: multiple processes might be running tests in parallel (like in Github Actions)

const siteIds: string[] = [];

for await (const site of client.sites.listPagedIterator()) {
// We don't want to destroy sites that might be used by other processes,
// let's only delete old ones

// biome-ignore lint/style/noNonNullAssertion: Always present
if (isOldEnough(site.created_at!)) {
siteIds.push(site.id);
}
}

await Promise.all(
siteIds.map(async (id) => {
try {
await client.sites.destroy(id);
} catch (e) {
if (e instanceof ApiError && e.findError('NOT_FOUND')) {
// Other processes might have already deleted the project
return;
}

throw e;
}
}),
);
};
10 changes: 6 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
preset: "ts-jest",
testEnvironment: "node",
testTimeout: 60000,
testMatch: ['**/*.test.ts'],
testMatch: ["**/*.test.ts"],
transformIgnorePatterns: [
'/packages/cma-client-node/node_modules/(?!(got|p-cancelable|@szmarczak|lowercase-keys)/)',
"/packages/cma-client-node/node_modules/(?!(got|p-cancelable|@szmarczak|lowercase-keys)/)",
],
setupFiles: ["dotenv/config"],
globalSetup: "./jest-helpers/globalSetup.ts",
// collectCoverage: true,
// collectCoverageFrom: [
// 'packages/**/*.[jt]s?(x)',
Expand Down
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"rome": "^11.0.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
"typescript": "^4.6.3",
"dotenv": "^16.4.1"
},
"homepage": "https://github.com/datocms/js-rest-api-clients",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cma-client-node/__tests__/publicInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ describe('Public info', () => {
const client = await generateNewCmaClient();

const publicInfo = await client.publicInfo.find();
expect(publicInfo.name).toEqual('Project');
expect(publicInfo.name).toContain('Project');
});
});
11 changes: 8 additions & 3 deletions packages/cma-client-node/__tests__/site.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ describe('site', () => {
const client = await generateNewCmaClient();

const fetchedSite = await client.site.find();
expect(fetchedSite.name).toEqual('Project');
expect(fetchedSite.name).toContain('Project');

const updatedSite = await client.site.update({ name: 'New project' });
expect(updatedSite.name).toEqual('New project');
const randomString =
Math.random().toString(36).substring(7) + new Date().getTime();

const newName = `New project ${randomString}`;

const updatedSite = await client.site.update({ name: newName });
expect(updatedSite.name).toEqual(newName);
});
});

0 comments on commit ab51c7e

Please sign in to comment.