|
1 | 1 | //Imports |
2 | | - const processes = require("child_process") |
3 | | - const yaml = require("js-yaml") |
4 | | - const fs = require("fs") |
5 | | - const path = require("path") |
6 | | - const url = require("url") |
7 | | - const axios = require("axios") |
8 | | - const faker = require("faker") |
9 | | - const ejs = require("ejs") |
| 2 | +const processes = require("child_process") |
| 3 | +const yaml = require("js-yaml") |
| 4 | +const fs = require("fs") |
| 5 | +const path = require("path") |
| 6 | +const url = require("url") |
| 7 | +const axios = require("axios") |
| 8 | +const faker = require("faker") |
| 9 | +const ejs = require("ejs") |
10 | 10 |
|
11 | 11 | //Github action |
12 | | - const action = yaml.load(fs.readFileSync(path.join(__dirname, "../action.yml"), "utf8")) |
13 | | - action.defaults = Object.fromEntries(Object.entries(action.inputs).map(([key, {default:value}]) => [key, value])) |
14 | | - action.input = vars => Object.fromEntries([...Object.entries(action.defaults), ...Object.entries(vars)].map(([key, value]) => [`INPUT_${key.toLocaleUpperCase()}`, value])) |
15 | | - action.run = async (vars) => await new Promise((solve, reject) => { |
| 12 | +const action = yaml.load(fs.readFileSync(path.join(__dirname, "../action.yml"), "utf8")) |
| 13 | +action.defaults = Object.fromEntries(Object.entries(action.inputs).map(([key, { default: value }]) => [key, value])) |
| 14 | +action.input = vars => Object.fromEntries([...Object.entries(action.defaults), ...Object.entries(vars)].map(([key, value]) => [`INPUT_${key.toLocaleUpperCase()}`, value])) |
| 15 | +action.run = async vars => |
| 16 | + await new Promise((solve, reject) => { |
16 | 17 | let [stdout, stderr] = ["", ""] |
17 | | - const env = {...process.env, ...action.input(vars), GITHUB_REPOSITORY:"lowlighter/metrics"} |
18 | | - const child = processes.spawn("node", ["source/app/action/index.mjs"], {env}) |
| 18 | + const env = { ...process.env, ...action.input(vars), GITHUB_REPOSITORY: "lowlighter/metrics" } |
| 19 | + const child = processes.spawn("node", ["source/app/action/index.mjs"], { env }) |
19 | 20 | child.stdout.on("data", data => stdout += data) |
20 | 21 | child.stderr.on("data", data => stderr += data) |
21 | 22 | child.on("close", code => { |
|
27 | 28 | }) |
28 | 29 |
|
29 | 30 | //Web instance |
30 | | - const web = {} |
31 | | - web.run = async (vars) => (await axios(`http://localhost:3000/lowlighter?${new url.URLSearchParams(Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])))}`)).status === 200 |
32 | | - web.start = async () => new Promise(solve => { |
| 31 | +const web = {} |
| 32 | +web.run = async vars => (await axios(`http://localhost:3000/lowlighter?${new url.URLSearchParams(Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])))}`)).status === 200 |
| 33 | +web.start = async () => |
| 34 | + new Promise(solve => { |
33 | 35 | let stdout = "" |
34 | | - web.instance = processes.spawn("node", ["source/app/web/index.mjs"], {env:{...process.env, USE_MOCKED_DATA:true, NO_SETTINGS:true}}) |
| 36 | + web.instance = processes.spawn("node", ["source/app/web/index.mjs"], { env: { ...process.env, USE_MOCKED_DATA: true, NO_SETTINGS: true } }) |
35 | 37 | web.instance.stdout.on("data", data => (stdout += data, /Server ready !/.test(stdout) ? solve() : null)) |
36 | 38 | web.instance.stderr.on("data", data => console.error(`${data}`)) |
37 | 39 | }) |
38 | | - web.stop = async () => await web.instance.kill("SIGKILL") |
| 40 | +web.stop = async () => await web.instance.kill("SIGKILL") |
39 | 41 |
|
40 | 42 | //Web instance placeholder |
41 | | - require("./../source/app/web/statics/app.placeholder.js") |
42 | | - const placeholder = globalThis.placeholder |
43 | | - delete globalThis.placeholder |
44 | | - placeholder.init({faker, ejs, axios:{async get(url) { return axios(`http://localhost:3000${url}`) }}}) |
45 | | - placeholder.run = async (vars) => { |
46 | | - const options = Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])) |
47 | | - const enabled = Object.fromEntries(Object.entries(vars).filter(([key]) => /^plugin_[a-z]+$/.test(key))) |
48 | | - const config = Object.fromEntries(Object.entries(options).filter(([key]) => /^config[.]/.test(key))) |
49 | | - const base = Object.fromEntries(Object.entries(options).filter(([key]) => /^base[.]/.test(key))) |
50 | | - return typeof await placeholder({ |
51 | | - templates:{selected:vars.template}, |
52 | | - plugins:{enabled:{...enabled, base}, options}, |
53 | | - config, |
54 | | - version:"TEST", |
55 | | - user:"lowlighter", |
56 | | - avatar:"https://github.com/lowlighter.png", |
57 | | - }) === "string" |
58 | | - } |
| 43 | +require("./../source/app/web/statics/app.placeholder.js") |
| 44 | +const placeholder = globalThis.placeholder |
| 45 | +delete globalThis.placeholder |
| 46 | +placeholder.init({ |
| 47 | + faker, |
| 48 | + ejs, |
| 49 | + axios: { |
| 50 | + async get(url) { |
| 51 | + return axios(`http://localhost:3000${url}`) |
| 52 | + }, |
| 53 | + }, |
| 54 | +}) |
| 55 | +placeholder.run = async vars => { |
| 56 | + const options = Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])) |
| 57 | + const enabled = Object.fromEntries(Object.entries(vars).filter(([key]) => /^plugin_[a-z]+$/.test(key))) |
| 58 | + const config = Object.fromEntries(Object.entries(options).filter(([key]) => /^config[.]/.test(key))) |
| 59 | + const base = Object.fromEntries(Object.entries(options).filter(([key]) => /^base[.]/.test(key))) |
| 60 | + return typeof await placeholder({ |
| 61 | + templates: { selected: vars.template }, |
| 62 | + plugins: { enabled: { ...enabled, base }, options }, |
| 63 | + config, |
| 64 | + version: "TEST", |
| 65 | + user: "lowlighter", |
| 66 | + avatar: "https://github.com/lowlighter.png", |
| 67 | + }) === "string" |
| 68 | +} |
59 | 69 |
|
60 | 70 | //Setup |
61 | | - beforeAll(async done => { |
62 | | - //Clean community template |
63 | | - await fs.promises.rmdir(path.join(__dirname, "../source/templates/@classic"), {recursive:true}) |
64 | | - //Start web instance |
65 | | - await web.start() |
66 | | - done() |
67 | | - }) |
| 71 | +beforeAll(async done => { |
| 72 | + //Clean community template |
| 73 | + await fs.promises.rmdir(path.join(__dirname, "../source/templates/@classic"), { recursive: true }) |
| 74 | + //Start web instance |
| 75 | + await web.start() |
| 76 | + done() |
| 77 | +}) |
68 | 78 | //Teardown |
69 | | - afterAll(async done => { |
70 | | - //Stop web instance |
71 | | - await web.stop() |
72 | | - //Clean community template |
73 | | - await fs.promises.rmdir(path.join(__dirname, "../source/templates/@classic"), {recursive:true}) |
74 | | - done() |
75 | | - }) |
| 79 | +afterAll(async done => { |
| 80 | + //Stop web instance |
| 81 | + await web.stop() |
| 82 | + //Clean community template |
| 83 | + await fs.promises.rmdir(path.join(__dirname, "../source/templates/@classic"), { recursive: true }) |
| 84 | + done() |
| 85 | +}) |
76 | 86 |
|
77 | 87 | //Load metadata (as jest doesn't support ESM modules, we use this dirty hack) |
78 | | - const metadata = JSON.parse(`${processes.spawnSync("node", [ |
79 | | - "--input-type", "module", |
80 | | - "--eval", 'import metadata from "./source/app/metrics/metadata.mjs";console.log(JSON.stringify(await metadata({log:false})))' |
81 | | - ]).stdout}`) |
| 88 | +const metadata = JSON.parse(`${ |
| 89 | + processes.spawnSync("node", [ |
| 90 | + "--input-type", |
| 91 | + "module", |
| 92 | + "--eval", |
| 93 | + 'import metadata from "./source/app/metrics/metadata.mjs";console.log(JSON.stringify(await metadata({log:false})))', |
| 94 | + ]).stdout |
| 95 | +}`) |
82 | 96 |
|
83 | 97 | //Build tests index |
84 | | - const tests = [] |
85 | | - for (const name in metadata.plugins) { |
86 | | - const cases = yaml |
87 | | - .load(fs.readFileSync(path.join(__dirname, "../source/plugins", name, "tests.yml"), "utf8")) |
88 | | - .map(({name:test, with:inputs, modes = [], timeout}) => { |
89 | | - const skip = new Set(Object.entries(metadata.templates).filter(([_, {readme:{compatibility}}]) => !compatibility[name]).map(([template]) => template)) |
90 | | - if (!(metadata.plugins[name].supports.includes("repository"))) |
91 | | - skip.add("repository") |
92 | | - return [test, inputs, {skip:[...skip], modes, timeout}] |
93 | | - }) |
94 | | - tests.push(...cases) |
95 | | - } |
| 98 | +const tests = [] |
| 99 | +for (const name in metadata.plugins) { |
| 100 | + const cases = yaml |
| 101 | + .load(fs.readFileSync(path.join(__dirname, "../source/plugins", name, "tests.yml"), "utf8")) |
| 102 | + .map(({ name: test, with: inputs, modes = [], timeout }) => { |
| 103 | + const skip = new Set(Object.entries(metadata.templates).filter(([_, { readme: { compatibility } }]) => !compatibility[name]).map(([template]) => template)) |
| 104 | + if (!(metadata.plugins[name].supports.includes("repository"))) |
| 105 | + skip.add("repository") |
| 106 | + return [test, inputs, { skip: [...skip], modes, timeout }] |
| 107 | + }) |
| 108 | + tests.push(...cases) |
| 109 | +} |
96 | 110 |
|
97 | 111 | //Tests run |
98 | | - describe("GitHub Action", () => |
99 | | - describe.each([ |
100 | | - ["classic", {}], |
101 | | - ["terminal", {}], |
102 | | - ["repository", {repo:"metrics"}], |
103 | | - ])("Template : %s", (template, query) => { |
104 | | - for (const [name, input, {skip = [], modes = [], timeout} = {}] of tests) |
105 | | - if ((skip.includes(template))||((modes.length)&&(!modes.includes("action")))) |
106 | | - test.skip(name, () => null) |
107 | | - else |
108 | | - test(name, async () => expect(await action.run({template, base:"", query:JSON.stringify(query), plugins_errors_fatal:true, dryrun:true, use_mocked_data:true, verify:true, ...input})).toBe(true), timeout) |
109 | | - }) |
110 | | - ) |
| 112 | +describe("GitHub Action", () => |
| 113 | + describe.each([ |
| 114 | + ["classic", {}], |
| 115 | + ["terminal", {}], |
| 116 | + ["repository", { repo: "metrics" }], |
| 117 | + ])("Template : %s", (template, query) => { |
| 118 | + for (const [name, input, { skip = [], modes = [], timeout } = {}] of tests) { |
| 119 | + if ((skip.includes(template)) || ((modes.length) && (!modes.includes("action")))) |
| 120 | + test.skip(name, () => null) |
| 121 | + else |
| 122 | + test(name, async () => expect(await action.run({ template, base: "", query: JSON.stringify(query), plugins_errors_fatal: true, dryrun: true, use_mocked_data: true, verify: true, ...input })).toBe(true), timeout) |
| 123 | + } |
| 124 | + })) |
111 | 125 |
|
112 | | - describe("Web instance", () => |
113 | | - describe.each([ |
114 | | - ["classic", {}], |
115 | | - ["terminal", {}], |
116 | | - ["repository", {repo:"metrics"}], |
117 | | - ])("Template : %s", (template, query) => { |
118 | | - for (const [name, input, {skip = [], modes = [], timeout} = {}] of tests) |
119 | | - if ((skip.includes(template))||((modes.length)&&(!modes.includes("web")))) |
120 | | - test.skip(name, () => null) |
121 | | - else |
122 | | - test(name, async () => expect(await web.run({template, base:0, ...query, plugins_errors_fatal:true, verify:true, ...input})).toBe(true), timeout) |
123 | | - }) |
124 | | - ) |
| 126 | +describe("Web instance", () => |
| 127 | + describe.each([ |
| 128 | + ["classic", {}], |
| 129 | + ["terminal", {}], |
| 130 | + ["repository", { repo: "metrics" }], |
| 131 | + ])("Template : %s", (template, query) => { |
| 132 | + for (const [name, input, { skip = [], modes = [], timeout } = {}] of tests) { |
| 133 | + if ((skip.includes(template)) || ((modes.length) && (!modes.includes("web")))) |
| 134 | + test.skip(name, () => null) |
| 135 | + else |
| 136 | + test(name, async () => expect(await web.run({ template, base: 0, ...query, plugins_errors_fatal: true, verify: true, ...input })).toBe(true), timeout) |
| 137 | + } |
| 138 | + })) |
125 | 139 |
|
126 | | - describe("Web instance (placeholder)", () => |
127 | | - describe.each([ |
128 | | - ["classic", {}], |
129 | | - ["terminal", {}], |
130 | | - ])("Template : %s", (template, query) => { |
131 | | - for (const [name, input, {skip = [], modes = [], timeout} = {}] of tests) |
132 | | - if ((skip.includes(template))||((modes.length)&&(!modes.includes("placeholder")))) |
133 | | - test.skip(name, () => null) |
134 | | - else |
135 | | - test(name, async () => expect(await placeholder.run({template, base:0, ...query, ...input})).toBe(true), timeout) |
136 | | - }) |
137 | | - ) |
| 140 | +describe("Web instance (placeholder)", () => |
| 141 | + describe.each([ |
| 142 | + ["classic", {}], |
| 143 | + ["terminal", {}], |
| 144 | + ])("Template : %s", (template, query) => { |
| 145 | + for (const [name, input, { skip = [], modes = [], timeout } = {}] of tests) { |
| 146 | + if ((skip.includes(template)) || ((modes.length) && (!modes.includes("placeholder")))) |
| 147 | + test.skip(name, () => null) |
| 148 | + else |
| 149 | + test(name, async () => expect(await placeholder.run({ template, base: 0, ...query, ...input })).toBe(true), timeout) |
| 150 | + } |
| 151 | + })) |
0 commit comments