Skip to content

Commit a16c1fd

Browse files
Merge pull request #214 from gridaco/playground
Testing env
2 parents fe8854d + 3e61f7c commit a16c1fd

3 files changed

Lines changed: 129 additions & 53 deletions

File tree

testing/report/report.config.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
const env = require("dotenv").config();
1+
const path = require("path");
22

3-
const { OUTDIR, LOCAL_ARCHIVE_FILE, LOCAL_ARCHIVE_IMAGE } = env;
3+
require("dotenv").config({
4+
path: path.join(__dirname, ".env"),
5+
});
6+
7+
const { OUTDIR, LOCAL_ARCHIVE_FILES, LOCAL_ARCHIVE_IMAGES } = process.env;
48

59
module.exports = {
6-
sample: "../../data/figma-archives/dev/meta.json",
10+
sample: path.join(__dirname, "../../data/figma-archives/prod/meta.json"),
711
outDir: OUTDIR,
812
localarchive: {
9-
file: LOCAL_ARCHIVE_FILE,
10-
image: LOCAL_ARCHIVE_IMAGE,
13+
files: LOCAL_ARCHIVE_FILES,
14+
images: LOCAL_ARCHIVE_IMAGES,
1115
},
1216
skipIfReportExists: true,
1317
};

testing/report/src/index.ts

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import path from "path";
22
import fs from "fs/promises";
3-
import { existsSync as exists } from "fs";
43
import assert from "assert";
54
import ora from "ora";
65
import { mapper } from "@design-sdk/figma-remote";
@@ -20,51 +19,75 @@ import { RemoteImageRepositories } from "@design-sdk/figma-remote/asset-reposito
2019

2120
setupCache(axios);
2221

23-
const mkdir = (path: string) => !exists(path) && fs.mkdir(path);
22+
const exists = async (path: string) => {
23+
try {
24+
await fs.access(path);
25+
return true;
26+
} catch (e) {
27+
return false;
28+
}
29+
};
30+
31+
const mkdir = async (path: string) =>
32+
!(await exists(path)) && (await fs.mkdir(path));
2433

2534
interface ReportConfig {
2635
sample: string;
2736
outDir?: string;
2837
localarchive?: {
29-
file: string;
30-
image: string;
38+
files: string;
39+
images: string;
3140
};
3241
skipIfReportExists?: boolean;
3342
}
3443

3544
// disable logging
3645
console.log = () => {};
37-
console.info = () => {};
3846
console.warn = () => {};
3947
console.error = () => {};
4048

4149
async function report() {
50+
console.info("Starting report");
4251
const cwd = process.cwd();
4352
// read the config
4453
const config: ReportConfig = require(path.join(cwd, "report.config.js"));
4554

4655
// load the sample file
47-
const samples_path = path.join(cwd, config.sample);
56+
const samples_path = (await exists(config.sample))
57+
? config.sample
58+
: path.join(cwd, config.sample);
59+
60+
assert(
61+
await exists(samples_path),
62+
`sample file not found at ${config.sample} nor ${samples_path}`
63+
);
64+
4865
const samples = JSON.parse(await fs.readFile(samples_path, "utf-8"));
4966

5067
// create .coverage folder
5168
const coverage_path = config.outDir ?? path.join(cwd, ".coverage");
52-
mkdir(coverage_path);
69+
70+
console.info(`Loaded ${samples.length} samples`);
71+
console.info(`Configuration used - ${JSON.stringify(config, null, 2)}`);
72+
73+
await mkdir(coverage_path);
5374

5475
const client = Client({
5576
paths: {
56-
file: config.localarchive.file,
57-
image: config.localarchive.image,
77+
files: config.localarchive.files,
78+
images: config.localarchive.images,
5879
},
5980
});
6081

6182
const ssworker = new ScreenshotWorker({});
6283
await ssworker.launch();
6384

85+
let i = 0;
6486
for (const c of samples) {
87+
i++;
6588
// create .coverage/:id folder
6689
const coverage_set_path = path.join(coverage_path, c.id);
67-
mkdir(coverage_set_path);
90+
await mkdir(coverage_set_path);
6891

6992
const { id: filekey } = c;
7093
let file;
@@ -93,21 +116,26 @@ async function report() {
93116
})
94117
).data.images;
95118
} catch (e) {
96-
console.error("exports not ready for", filekey);
119+
console.error("exports not ready for", filekey, e.message);
97120
continue;
98121
}
99122

123+
let ii = 0;
100124
for (const frame of frames) {
101-
const spinner = ora(`Running coverage for ${c.id}/${frame.id}`).start();
125+
ii++;
126+
127+
const spinner = ora(
128+
`[${i}/${samples.length}] Running coverage for ${c.id}/${frame.id} (${ii}/${frames.length})`
129+
).start();
102130

103131
// create .coverage/:id/:node folder
104132
const coverage_node_path = path.join(coverage_set_path, frame.id);
105-
mkdir(coverage_node_path);
133+
await mkdir(coverage_node_path);
106134

107135
// report.json
108136
const report_file = path.join(coverage_node_path, "report.json");
109137
if (config.skipIfReportExists) {
110-
if (exists(report_file)) {
138+
if (await exists(report_file)) {
111139
spinner.succeed(`Skipping - report for ${frame.id} already exists`);
112140
continue;
113141
}
@@ -134,6 +162,37 @@ async function report() {
134162
);
135163

136164
try {
165+
// image A (original)
166+
const exported = exports[frame.id];
167+
const image_a_rel = "./a.png";
168+
const image_a = path.join(coverage_node_path, image_a_rel);
169+
// download the exported image with url
170+
// if the exported is local fs path, then use copy instead
171+
if (await exists(exported)) {
172+
try {
173+
// copy file with symlink
174+
// rempve if already exists before linking new one
175+
if (await exists(image_a)) {
176+
await fs.unlink(image_a);
177+
}
178+
await fs.symlink(exported, image_a);
179+
} catch (e) {
180+
// TODO: symlink still fails with "EEXIST: file already exists, symlink"
181+
// we need to handle this.
182+
// reason? - unknown
183+
}
184+
} else if (exported.startsWith("http")) {
185+
const dl = await axios.get(exported, { responseType: "arraybuffer" });
186+
await fs.writeFile(image_a, dl.data);
187+
} else {
188+
throw new Error(`File not found - ${exported}`);
189+
}
190+
191+
if (!(await exists(image_a))) {
192+
spinner.fail(`Image A not found - ${image_a}`);
193+
continue;
194+
}
195+
137196
// codegen
138197
const code = await htmlcss(
139198
{
@@ -165,23 +224,6 @@ async function report() {
165224
const image_b = path.join(coverage_node_path, image_b_rel);
166225
await fs.writeFile(image_b, screenshot_buffer);
167226

168-
const exported = exports[frame.id];
169-
const image_a_rel = "./a.png";
170-
const image_a = path.join(coverage_node_path, image_a_rel);
171-
// download the exported image with url
172-
// if the exported is local fs path, then use copy instead
173-
if (exists(exported)) {
174-
// copy file with symlink
175-
// unlink if exists
176-
if (exists(image_a)) {
177-
await fs.unlink(image_a);
178-
}
179-
await fs.symlink(exported, image_a);
180-
} else {
181-
const dl = await axios.get(exported, { responseType: "arraybuffer" });
182-
await fs.writeFile(image_a, dl.data);
183-
}
184-
185227
const diff = await resemble(image_a, image_b);
186228
const diff_file = path.join(coverage_node_path, "diff.png");
187229
// write diff.png
@@ -224,6 +266,13 @@ async function report() {
224266
spinner.fail(`error on ${frame.id} : ${e.message}`);
225267
}
226268
}
269+
270+
// cleaup
271+
// if the coverage is empty, remove the folder
272+
const files = await fs.readdir(coverage_set_path);
273+
if (files.length === 0) {
274+
await fs.rmdir(coverage_set_path);
275+
}
227276
}
228277

229278
// cleaup

testing/testing-screenshot/index.ts

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ interface ScreenshotOptions {
88
};
99
}
1010

11-
export async function screenshot({ htmlcss, viewport }: ScreenshotOptions) {
12-
const worker = new Worker({});
13-
await worker.launch();
14-
const buffer = worker.screenshot({ htmlcss, viewport });
15-
await worker.terminate();
16-
return buffer;
17-
}
18-
1911
export class Worker {
2012
private browser: Browser;
2113
private page: Page;
@@ -40,22 +32,53 @@ export class Worker {
4032
return this.browser;
4133
}
4234

35+
async relaunch() {
36+
await this.close();
37+
return this.launch();
38+
}
39+
4340
async screenshot({ htmlcss, viewport }: ScreenshotOptions) {
44-
this.page.setViewport(viewport);
45-
await this.page.setContent(htmlcss, { waitUntil: "networkidle0" });
46-
const buffer = await this.page.screenshot({
47-
type: "png",
48-
// support transparency
49-
omitBackground: true,
50-
});
51-
return buffer;
41+
try {
42+
if (!this.browser || !this.page || this.page.isClosed()) {
43+
await this.relaunch();
44+
}
45+
await this.page.setViewport(viewport);
46+
await this.page.setContent(htmlcss, { waitUntil: "networkidle0" });
47+
const buffer = await this.page.screenshot({
48+
type: "png",
49+
// support transparency
50+
omitBackground: true,
51+
});
52+
return buffer;
53+
} catch (error) {
54+
console.log(`Failed to take screenshot: ${error.message}`);
55+
await this.relaunch();
56+
// After relaunch, retry taking screenshot or rethrow the error
57+
return this.screenshot({ htmlcss, viewport });
58+
}
5259
}
5360

5461
async close() {
55-
await this.browser.close();
62+
if (this.browser) {
63+
try {
64+
await this.browser.close();
65+
} catch (e) {
66+
console.log(`Failed to close browser: ${e.message}`);
67+
}
68+
this.browser = null;
69+
this.page = null;
70+
}
5671
}
5772

5873
terminate() {
5974
this.close();
6075
}
6176
}
77+
78+
export async function screenshot(options: ScreenshotOptions) {
79+
const worker = new Worker({});
80+
await worker.launch();
81+
const buffer = await worker.screenshot(options);
82+
await worker.terminate();
83+
return buffer;
84+
}

0 commit comments

Comments
 (0)