Skip to content

Testing env #214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions testing/report/report.config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
const env = require("dotenv").config();
const path = require("path");

const { OUTDIR, LOCAL_ARCHIVE_FILE, LOCAL_ARCHIVE_IMAGE } = env;
require("dotenv").config({
path: path.join(__dirname, ".env"),
});

const { OUTDIR, LOCAL_ARCHIVE_FILES, LOCAL_ARCHIVE_IMAGES } = process.env;

module.exports = {
sample: "../../data/figma-archives/dev/meta.json",
sample: path.join(__dirname, "../../data/figma-archives/prod/meta.json"),
outDir: OUTDIR,
localarchive: {
file: LOCAL_ARCHIVE_FILE,
image: LOCAL_ARCHIVE_IMAGE,
files: LOCAL_ARCHIVE_FILES,
images: LOCAL_ARCHIVE_IMAGES,
},
skipIfReportExists: true,
};
111 changes: 80 additions & 31 deletions testing/report/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from "path";
import fs from "fs/promises";
import { existsSync as exists } from "fs";
import assert from "assert";
import ora from "ora";
import { mapper } from "@design-sdk/figma-remote";
Expand All @@ -20,51 +19,75 @@ import { RemoteImageRepositories } from "@design-sdk/figma-remote/asset-reposito

setupCache(axios);

const mkdir = (path: string) => !exists(path) && fs.mkdir(path);
const exists = async (path: string) => {
try {
await fs.access(path);
return true;
} catch (e) {
return false;
}
};

const mkdir = async (path: string) =>
!(await exists(path)) && (await fs.mkdir(path));

interface ReportConfig {
sample: string;
outDir?: string;
localarchive?: {
file: string;
image: string;
files: string;
images: string;
};
skipIfReportExists?: boolean;
}

// disable logging
console.log = () => {};
console.info = () => {};
console.warn = () => {};
console.error = () => {};

async function report() {
console.info("Starting report");
const cwd = process.cwd();
// read the config
const config: ReportConfig = require(path.join(cwd, "report.config.js"));

// load the sample file
const samples_path = path.join(cwd, config.sample);
const samples_path = (await exists(config.sample))
? config.sample
: path.join(cwd, config.sample);

assert(
await exists(samples_path),
`sample file not found at ${config.sample} nor ${samples_path}`
);

const samples = JSON.parse(await fs.readFile(samples_path, "utf-8"));

// create .coverage folder
const coverage_path = config.outDir ?? path.join(cwd, ".coverage");
mkdir(coverage_path);

console.info(`Loaded ${samples.length} samples`);
console.info(`Configuration used - ${JSON.stringify(config, null, 2)}`);

await mkdir(coverage_path);

const client = Client({
paths: {
file: config.localarchive.file,
image: config.localarchive.image,
files: config.localarchive.files,
images: config.localarchive.images,
},
});

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

let i = 0;
for (const c of samples) {
i++;
// create .coverage/:id folder
const coverage_set_path = path.join(coverage_path, c.id);
mkdir(coverage_set_path);
await mkdir(coverage_set_path);

const { id: filekey } = c;
let file;
Expand Down Expand Up @@ -93,21 +116,26 @@ async function report() {
})
).data.images;
} catch (e) {
console.error("exports not ready for", filekey);
console.error("exports not ready for", filekey, e.message);
continue;
}

let ii = 0;
for (const frame of frames) {
const spinner = ora(`Running coverage for ${c.id}/${frame.id}`).start();
ii++;

const spinner = ora(
`[${i}/${samples.length}] Running coverage for ${c.id}/${frame.id} (${ii}/${frames.length})`
).start();

// create .coverage/:id/:node folder
const coverage_node_path = path.join(coverage_set_path, frame.id);
mkdir(coverage_node_path);
await mkdir(coverage_node_path);

// report.json
const report_file = path.join(coverage_node_path, "report.json");
if (config.skipIfReportExists) {
if (exists(report_file)) {
if (await exists(report_file)) {
spinner.succeed(`Skipping - report for ${frame.id} already exists`);
continue;
}
Expand All @@ -134,6 +162,37 @@ async function report() {
);

try {
// image A (original)
const exported = exports[frame.id];
const image_a_rel = "./a.png";
const image_a = path.join(coverage_node_path, image_a_rel);
// download the exported image with url
// if the exported is local fs path, then use copy instead
if (await exists(exported)) {
try {
// copy file with symlink
// rempve if already exists before linking new one
if (await exists(image_a)) {
await fs.unlink(image_a);
}
await fs.symlink(exported, image_a);
} catch (e) {
// TODO: symlink still fails with "EEXIST: file already exists, symlink"
// we need to handle this.
// reason? - unknown
}
} else if (exported.startsWith("http")) {
const dl = await axios.get(exported, { responseType: "arraybuffer" });
await fs.writeFile(image_a, dl.data);
} else {
throw new Error(`File not found - ${exported}`);
}

if (!(await exists(image_a))) {
spinner.fail(`Image A not found - ${image_a}`);
continue;
}

// codegen
const code = await htmlcss(
{
Expand Down Expand Up @@ -165,23 +224,6 @@ async function report() {
const image_b = path.join(coverage_node_path, image_b_rel);
await fs.writeFile(image_b, screenshot_buffer);

const exported = exports[frame.id];
const image_a_rel = "./a.png";
const image_a = path.join(coverage_node_path, image_a_rel);
// download the exported image with url
// if the exported is local fs path, then use copy instead
if (exists(exported)) {
// copy file with symlink
// unlink if exists
if (exists(image_a)) {
await fs.unlink(image_a);
}
await fs.symlink(exported, image_a);
} else {
const dl = await axios.get(exported, { responseType: "arraybuffer" });
await fs.writeFile(image_a, dl.data);
}

const diff = await resemble(image_a, image_b);
const diff_file = path.join(coverage_node_path, "diff.png");
// write diff.png
Expand Down Expand Up @@ -224,6 +266,13 @@ async function report() {
spinner.fail(`error on ${frame.id} : ${e.message}`);
}
}

// cleaup
// if the coverage is empty, remove the folder
const files = await fs.readdir(coverage_set_path);
if (files.length === 0) {
await fs.rmdir(coverage_set_path);
}
}

// cleaup
Expand Down
57 changes: 40 additions & 17 deletions testing/testing-screenshot/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ interface ScreenshotOptions {
};
}

export async function screenshot({ htmlcss, viewport }: ScreenshotOptions) {
const worker = new Worker({});
await worker.launch();
const buffer = worker.screenshot({ htmlcss, viewport });
await worker.terminate();
return buffer;
}

export class Worker {
private browser: Browser;
private page: Page;
Expand All @@ -40,22 +32,53 @@ export class Worker {
return this.browser;
}

async relaunch() {
await this.close();
return this.launch();
}

async screenshot({ htmlcss, viewport }: ScreenshotOptions) {
this.page.setViewport(viewport);
await this.page.setContent(htmlcss, { waitUntil: "networkidle0" });
const buffer = await this.page.screenshot({
type: "png",
// support transparency
omitBackground: true,
});
return buffer;
try {
if (!this.browser || !this.page || this.page.isClosed()) {
await this.relaunch();
}
await this.page.setViewport(viewport);
await this.page.setContent(htmlcss, { waitUntil: "networkidle0" });
const buffer = await this.page.screenshot({
type: "png",
// support transparency
omitBackground: true,
});
return buffer;
} catch (error) {
console.log(`Failed to take screenshot: ${error.message}`);
await this.relaunch();
// After relaunch, retry taking screenshot or rethrow the error
return this.screenshot({ htmlcss, viewport });
}
}

async close() {
await this.browser.close();
if (this.browser) {
try {
await this.browser.close();
} catch (e) {
console.log(`Failed to close browser: ${e.message}`);
}
this.browser = null;
this.page = null;
}
}

terminate() {
this.close();
}
}

export async function screenshot(options: ScreenshotOptions) {
const worker = new Worker({});
await worker.launch();
const buffer = await worker.screenshot(options);
await worker.terminate();
return buffer;
}