-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathrecord-fixtures.js
170 lines (143 loc) · 5.18 KB
/
record-fixtures.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// @ts-check
import { readdir, writeFile } from "node:fs/promises";
import dotenv from "dotenv";
import { App } from "@octokit/app";
import Octokit from "./_lib/octokit.js";
import GitHubProject from "../../index.js";
import { clearTestProject } from "./_lib/clear-test-project.js";
import { deleteAllTestRepositories } from "./_lib/delete-all-test-repositories.js";
import { createRepository } from "./_lib/create-test-repository.js";
dotenv.config();
recordFixtures(process.argv.slice(2));
async function recordFixtures(selectedTestFolders) {
if (selectedTestFolders.length) {
console.log("Updating fixtures for %j", selectedTestFolders);
} else {
console.log("Updating all fixtures");
}
if (
!process.env.PROJECT_NUMBER ||
!process.env.GH_PROJECT_FIXTURES_APP_ID ||
!process.env.GH_PROJECT_FIXTURES_APP_PRIVATE_KEY
) {
throw new Error(
"PROJECT_NUMBER, GH_PROJECT_FIXTURES_APP_ID, and GH_PROJECT_FIXTURES_APP_PRIVATE_KEY are required. Add the them to your local `.env`"
);
}
const app = new App({
appId: process.env.GH_PROJECT_FIXTURES_APP_ID,
privateKey: process.env.GH_PROJECT_FIXTURES_APP_PRIVATE_KEY,
Octokit,
});
app.eachInstallation(async ({ installation, octokit }) => {
const projectNumber = Number(process.env.PROJECT_NUMBER);
// @ts-expect-error - we can be sure that installaction.account is set
const owner = String(installation.account.login);
// log what we are doing
octokit.hook.wrap("request", (request, options) => {
console.log(`[record] ${options.method} ${options.url}`);
if (options.url === "/graphql") {
// @ts-expect-error - options.query is always set for `/graphql` requests
console.log(" " + options.query.trim().split("\n")[0] + " … }");
}
return request(options);
});
// we use two project instances, one for setting up state, and
// the other for testing, without the two instances sharing internal state / caching.
const projectOptions = {
owner,
number: projectNumber,
octokit,
fields: {
text: "Text",
number: "Number",
date: "Date",
singleSelect: "Single select",
},
};
const testFolders = await readdir("test/recorded");
for (const testFolder of testFolders) {
if (
[`_lib`, `snapshots`].includes(testFolder) ||
testFolder.endsWith(`.js`)
) {
continue;
}
if (
testFolder === "api.items.list-with-pagination" &&
!selectedTestFolders.includes(testFolder)
) {
console.log(
"Skipping recording fixtures for 'api.items.list-with-pagination' because it takes forever to update. Record it explicitly with `node test/recorded/record-fixtures.js api.items.list-with-pagination`."
);
continue;
}
if (
selectedTestFolders.length &&
!selectedTestFolders.includes(testFolder)
) {
continue;
}
console.log("Recording fixtures for %s", testFolder);
const setupProject = new GitHubProject(projectOptions);
const testProject = new GitHubProject(projectOptions);
// create a clean slate
await clearTestProject(setupProject);
await deleteAllTestRepositories(process.env, octokit, owner);
// create a test repository
const repository = await createRepository(
process.env,
octokit,
owner,
testFolder
);
// import record and test scripts
const { prepare } = await import(`./${testFolder}/prepare.js`);
const { test } = await import(`./${testFolder}/test.js`);
// prepare recording fixtures
const args = await prepare(repository, octokit, setupProject);
// do the recording
const fixtures = [];
octokit.hook.wrap("request", async (request, options) => {
const response = await request(options);
fixtures.push({
query: options.query,
variables: options.variables,
response,
});
return response;
});
await test(testProject, ...args);
// normalize fixtures
const counters = {
databaseId: 1000,
};
const idMappings = {};
const fixturesJSON = JSON.stringify(fixtures, null, 2)
.replaceAll(
/"(id|projectId|contentId|itemId)": "([^_"]+)_([^"]+)"/g,
(match, key, prefix, id) => {
if (!idMappings[id]) {
if (!counters[prefix]) counters[prefix] = 0;
idMappings[id] = ++counters[prefix];
}
return `"${key}": "${prefix}_${idMappings[id]}"`;
}
)
.replaceAll(/"databaseId": (\d+)/g, (match, key, prefix, id) => {
if (!idMappings[id]) {
idMappings[id] = ++counters.databaseId;
}
return `"databaseId": ${idMappings[id]}`;
})
.replaceAll(repository.name, "test-repository")
.replaceAll(
/"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z"/g,
'"2022-02-02T12:00:00Z"'
);
const fixturesPath = `test/recorded/${testFolder}/fixtures.json`;
await writeFile(fixturesPath, fixturesJSON);
console.log("%s written", fixturesPath);
}
});
}