From 5e9fffd7d83115c8b558dfe8a62a48a280aaaa0c Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Fri, 20 Oct 2023 00:25:19 -0400 Subject: [PATCH] continue --- action.yml | 2 +- deno.jsonc | 3 +- deno.lock | 3 + source/metrics/engine/components/component.ts | 6 +- .../component_test.ts} | 55 +-------- .../engine/components/internal_test.ts | 14 +++ source/metrics/engine/components/plugin.ts | 9 +- .../metrics/engine/components/plugin_test.ts | 72 +++++++++++ source/metrics/engine/components/processor.ts | 8 +- .../engine/components/processor_test.ts | 60 +++++++++ source/metrics/engine/components/requests.ts | 2 +- .../engine/components/requests_test.ts | 63 ++++++++++ .../engine/components/tests/mock.graphql | 3 + .../engine/components/tests/mock.graphql.ts | 5 + .../engine/components/tests/mock.http.ts | 5 + .../components/tests/mock_missing.graphql | 3 + .../components/tests/mock_paginate.graphql | 11 ++ .../tests/mock_paginate_bad.graphql | 7 ++ .../metrics/engine/components/tests/rest.ts | 42 +++++++ source/metrics/utils/browser.ts | 2 +- source/plugins/calendar/tests/list.yml | 114 +++++++++++------- source/plugins/gists/tests/list.yml | 20 +-- source/plugins/introduction/tests/list.yml | 15 ++- source/plugins/lines/tests/list.yml | 100 +++++++++------ source/plugins/rss/tests/list.yml | 10 +- source/plugins/webscraping/tests/list.yml | 21 ++-- source/processors/assert/mod.ts | 27 +++-- source/processors/assert/tests/list.yml | 52 ++++---- source/processors/inject.content/mod.ts | 6 +- .../processors/inject.content/tests/list.yml | 16 ++- .../processors/inject.script/tests/list.yml | 5 +- source/processors/inject.style/tests/list.yml | 14 ++- source/processors/optimize.css/tests/list.yml | 20 +-- source/processors/optimize.svg/tests/list.yml | 9 +- source/processors/optimize.xml/tests/list.yml | 7 +- .../processors/render.gemojis/tests/list.yml | 12 +- .../processors/render.octicons/tests/list.yml | 25 ++-- .../processors/render.twemojis/tests/list.yml | 5 +- source/processors/render/tests/list.yml | 13 +- source/run/cli/mod.ts | 23 ++-- 40 files changed, 617 insertions(+), 272 deletions(-) rename source/metrics/engine/{components_test.ts => components/component_test.ts} (54%) create mode 100644 source/metrics/engine/components/internal_test.ts create mode 100644 source/metrics/engine/components/plugin_test.ts create mode 100644 source/metrics/engine/components/processor_test.ts create mode 100644 source/metrics/engine/components/requests_test.ts create mode 100644 source/metrics/engine/components/tests/mock.graphql create mode 100644 source/metrics/engine/components/tests/mock.graphql.ts create mode 100644 source/metrics/engine/components/tests/mock.http.ts create mode 100644 source/metrics/engine/components/tests/mock_missing.graphql create mode 100644 source/metrics/engine/components/tests/mock_paginate.graphql create mode 100644 source/metrics/engine/components/tests/mock_paginate_bad.graphql create mode 100644 source/metrics/engine/components/tests/rest.ts diff --git a/action.yml b/action.yml index 474d9fdf9f0..5a0b73aeb9a 100644 --- a/action.yml +++ b/action.yml @@ -8,7 +8,7 @@ branding: inputs: docker_image: description: Docker image to use - default: Dockerfile # TODO(@lowlighter): change to remote published image + default: ghcr.io/lowlighter/metrics:v4 required: true config: description: Configuration file diff --git a/deno.jsonc b/deno.jsonc index 9135244ee3d..d1176d5ac5c 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -13,7 +13,7 @@ "@processors/": "./source/processors/" }, "tasks": { - "qq": "rm -rf .coverage && deno test --coverage=.coverage --no-check --unstable --trace-ops --allow-all source/metrics/engine/metadata_test.ts && deno coverage .coverage --exclude='(secret|log|io|errors|testing|validation|format|version|config|requests|processor|plugin|internal|component).ts'", + "qq": "rm -rf .coverage && deno test --coverage=.coverage --no-check --unstable --trace-ops --allow-all source/metrics/engine/components/processor_test.ts && deno coverage .coverage --exclude='(secret|log|io|errors|testing|validation|format|version|config|processor|internal|requests|component).ts'", "q": "rm -rf .coverage && deno test --coverage=.coverage --unstable --trace-ops --fail-fast --allow-all source/metrics && deno coverage .coverage", "btr": "deno run --allow-env --allow-read --allow-write=.btr.json --allow-run=deno --no-lock tasks.ts $0" }, @@ -96,7 +96,6 @@ "doc": true, "traceOps": true, //"parallel": true, - "shuffle": true, "coverage": ".coverage", "failFast": 1, "lock": false, diff --git a/deno.lock b/deno.lock index 7fe722d1194..fd01fbc605d 100644 --- a/deno.lock +++ b/deno.lock @@ -12,6 +12,7 @@ } }, "redirects": { + "https://esm.sh/gh/lino-levan/astral@main/mod.ts": "https://esm.sh/gh/lino-levan/astral@2e82aeb3a8/mod.ts", "https://esm.sh/gh/lowlighter/astral@feat-support-existing-ws-endpoint/mod.ts": "https://esm.sh/gh/lowlighter/astral@42f070c029/mod.ts", "https://esm.sh/gh/lowlighter/astral@fix-dont-require-env-perms-with-cache/mod.ts": "https://esm.sh/gh/lowlighter/astral@de2021a416/mod.ts", "https://esm.sh/gh/lowlighter/astral@fork/mod.ts": "https://esm.sh/gh/lowlighter/astral@8932dabbb2/mod.ts", @@ -406,6 +407,7 @@ "https://esm.sh/compare-versions@6.1.0": "201fa5a67808b194128313e2aa2e4305fad94f2366eb28d86051bf084cca2931", "https://esm.sh/csso@5.0.5": "337688fa652a52757a5562702a9047bde37af888e61031de951ca39f389e56c0", "https://esm.sh/ejs@3.1.9": "11987a85eed88dc3354455d74cb5fb4caf09cab6eb692721813e00ec4ddb9678", + "https://esm.sh/gh/lino-levan/astral@2e82aeb3a8/mod.ts": "8de05358d8a63993961525f28f944e3d7868dabb1c6a80a7eff69c4ec4eb35ae", "https://esm.sh/gh/lowlighter/astral@3f30872dd3/mod.ts": "007b17bdf37ba61f77caa86c1c425a9c2a727cdb2fb5bf6b5c49f3bc0e3c890c", "https://esm.sh/gh/lowlighter/astral@42f070c029/mod.ts": "e0dcada31b0d0fb7452e0ffebf8c182a4e5704ca6f6d394993b11b976f801b1e", "https://esm.sh/gh/lowlighter/astral@51c296e2bf/mod.ts": "26c67ff3b8e2141a76d92797e0aa9e6ff7e2cc40811bceded112348f1fd7a236", @@ -539,6 +541,7 @@ "https://esm.sh/v133/chai-subset@1.6.0/denonext/chai-subset.mjs": "009fd018f8bd802311ca02092056f1c25b2e84888c742cb14667b28ad308f041", "https://esm.sh/v133/deprecation@2.3.1/denonext/deprecation.mjs": "0bf7139d1068345709e59dddb4daea315691d290a8c896a6e076dea02dd66eaf", "https://esm.sh/v133/ejs@3.1.9/denonext/ejs.mjs": "30fabad57b39bf90ea47cf5df77b683f4cca4622a438b47c2a1e73a077608127", + "https://esm.sh/v133/gh/lino-levan/astral@2e82aeb3a8/denonext/mod.ts.js": "a684c1ed0ab4e3bb0fa417619c2b974a4a3b17b9ea60e1ee10ec71e68ba48f1c", "https://esm.sh/v133/gh/lowlighter/astral@3f30872dd3/denonext/mod.ts.js": "c8cb92820668c019200c50ffd5a0effdaab478bf8c16f6c7cb2adb42b180c51d", "https://esm.sh/v133/gh/lowlighter/astral@42f070c029/denonext/mod.ts.js": "ee18be3485eb199922e0797fbad31d961414437274d7f393629328426b477e92", "https://esm.sh/v133/gh/lowlighter/astral@51c296e2bf/denonext/mod.ts.js": "46cce1bc0bdff4be2fc274c3b86df84b56d00e60d96e80bc6dc893603cf0ade9", diff --git a/source/metrics/engine/components/component.ts b/source/metrics/engine/components/component.ts index 42433f6d6a5..17b01e812f0 100644 --- a/source/metrics/engine/components/component.ts +++ b/source/metrics/engine/components/component.ts @@ -43,14 +43,14 @@ export abstract class Component extends Internal { /** Icon */ get icon() { - return this.name.match(/(\p{Emoji_Presentation}+)/gu)?.[0] ?? "⏹️" + return this.name.match(/([\p{Emoji}\u200d]+)/gu)?.[0] ?? "⏹️" } /** Action */ protected abstract action(state: state): Promise /** Is supported ? */ - protected abstract supported(): void + protected abstract supported(state: state): Promise | void /** Run component */ protected async run(state: state) { @@ -65,7 +65,7 @@ export abstract class Component extends Internal { try { // Ensure component is supported for current context try { - this.supported() + await this.supported(state) } catch (error) { recoverable = false throw error diff --git a/source/metrics/engine/components_test.ts b/source/metrics/engine/components/component_test.ts similarity index 54% rename from source/metrics/engine/components_test.ts rename to source/metrics/engine/components/component_test.ts index b2704afa5c5..ae5b9a66792 100644 --- a/source/metrics/engine/components_test.ts +++ b/source/metrics/engine/components/component_test.ts @@ -1,14 +1,12 @@ -import { expect, test } from "@utils/testing.ts" -import { Plugin } from "@engine/components/plugin.ts" -import { Processor } from "@engine/components/processor.ts" -import { process } from "@engine/process.ts" +import { test } from "@utils/testing.ts" import { deepMerge } from "std/collections/deep_merge.ts" import { Browser } from "@utils/browser.ts" import * as dir from "@engine/paths.ts" import { Logger } from "@utils/log.ts" import { Component } from "@engine/components/component.ts" -const config = { +/** Config */ +export const config = { presets: { default: { plugins: { @@ -22,51 +20,10 @@ const config = { }, }, }, -} - -// Plugins -for (const id of await Plugin.list()) { - const plugin = await Plugin.load({ id }) - const tests = await plugin.tests() - const templates = await plugin.templates() - const name = `${plugin.icon} plugins/${plugin.id}` - if (!tests.length) { - Deno.test.ignore(name, () => void null) - continue - } - for (const test of tests) { - Deno.test(`${name} | ${test.name}`, await getPermissions(test), async (t) => { - const { teardown } = setup() - for (const template of templates) { - await t.step(template, async () => { - await expect(process(deepMerge({ presets: { default: { plugins: { template } } } }, deepMerge(config, test, { arrays: "replace" })))).to.be.fulfilled.and.eventually.be.ok - }) - } - teardown() - }) - } -} - -// Processors -for (const id of await Processor.list()) { - const processor = await Processor.load({ id }) - const tests = await processor.tests() - const name = `${processor.icon} processors/${processor.id}` - if (!tests.length) { - Deno.test.ignore(name, () => void null) - continue - } - for (const test of tests) { - Deno.test(`${name} | ${test.name}`, await getPermissions(test), async () => { - const { teardown } = setup() - await expect(process(deepMerge(config, test, { arrays: "replace" }))).to.be.fulfilled.and.eventually.be.ok - teardown() - }) - } -} +} as const /** Setup for components tests */ -function setup() { +export function setup() { const { raw } = Logger const { shareable } = Browser Logger.raw = false @@ -79,7 +36,7 @@ function setup() { } /** Compute required permissions */ -async function getPermissions(test: Awaited>[0]) { +export async function getPermissions(test: Awaited>[0]) { // Aggregate permissions from all plugins and processors const requested = new Set() const components = new Set() diff --git a/source/metrics/engine/components/internal_test.ts b/source/metrics/engine/components/internal_test.ts new file mode 100644 index 00000000000..3b6c08576e9 --- /dev/null +++ b/source/metrics/engine/components/internal_test.ts @@ -0,0 +1,14 @@ +import { Internal } from "@engine/components/internal.ts" +import { expect, test } from "@utils/testing.ts" + +class InternalTest extends Internal { + protected static readonly meta = import.meta + constructor() { + super(null as test) + } +} + +Deno.test("Internal()", { permissions: "none" }, () => { + const internal = new InternalTest() + expect(internal.id).to.equal("metrics/engine/components/internal_test.ts") +}) diff --git a/source/metrics/engine/components/plugin.ts b/source/metrics/engine/components/plugin.ts index adaf1925c4a..0647f9d73ff 100644 --- a/source/metrics/engine/components/plugin.ts +++ b/source/metrics/engine/components/plugin.ts @@ -51,11 +51,6 @@ export abstract class Plugin extends Component { return this.requests.fetch(...args) } - /** Ratelimit */ - protected ratelimit() { - return this.requests.ratelimit() - } - /** Render an EJS template */ protected async render({ state }: { state: state }) { const name = this.context.template @@ -72,8 +67,8 @@ export abstract class Plugin extends Component { /** Is supported ? */ protected supported() { - if (!this.supports.includes(this.context.entity)) { - throws(`Not supported for ${this.context.entity}`) + if ((this.supports.length) && (!this.supports.includes(this.context.entity))) { + throws(`${this.id} not supported for ${this.context.entity}`) } } diff --git a/source/metrics/engine/components/plugin_test.ts b/source/metrics/engine/components/plugin_test.ts new file mode 100644 index 00000000000..5fa621a3d92 --- /dev/null +++ b/source/metrics/engine/components/plugin_test.ts @@ -0,0 +1,72 @@ +import { expect, MetricsError, test } from "@utils/testing.ts" +import { is, Plugin } from "@engine/components/plugin.ts" +import { config as schema } from "@engine/config.ts" +import { config, getPermissions, setup } from "@engine/components/component_test.ts" +import { deepMerge } from "std/collections/deep_merge.ts" +import { process } from "@engine/process.ts" +//import * as dir from "@engine/paths.ts" + +// TODO(@lowlighter): change to `[dir.source]` after https://github.com/denoland/deno_std/pull/3692 +Deno.test("Plugin()", { permissions: { read: true } }, async (t) => { + const { plugins: [context] } = schema.parse({ plugins: [{ id: "test", logs: "none", fatal: true, template: null, retries: { delay: 0 } }] }) as test + class TestPlugin extends Plugin { + static readonly meta = { url: "test" } as test + readonly name = "⚗️ Test plugin" + readonly category = "testing" + readonly supports = ["user"] + readonly description = "Test plugin" + readonly inputs = is.object({}) + readonly outputs = is.object({}) + protected async action() {} + async run() { + const state = await Plugin.state.parseAsync({ results: [], errors: [] }) + return super.run(state) + } + constructor(context: Plugin["context"]) { + super(context) + } + } + + await t.step("tests() returns a list of tests", async () => { + const plugin = new TestPlugin(context) + await expect(plugin.tests()).to.eventually.be.an("array") + }) + + await t.step("templates() returns a list of templates", async () => { + const plugin = new TestPlugin(context) + await expect(plugin.templates()).to.eventually.be.an("array") + }) + + await t.step("supported()", async (t) => { + await t.step("is a noop when entity is supported", async () => { + const plugin = new TestPlugin({ ...context, entity: "user" }) + await expect(plugin.run()).to.be.eventually.be.ok + }) + await t.step("throws if not supported", async () => { + const plugin = new TestPlugin({ ...context, entity: "organization" }) + await expect(plugin.run()).to.be.rejectedWith(MetricsError, /not supported for organization/i) + }) + }) +}) + +for (const id of await Plugin.list()) { + const plugin = await Plugin.load({ id }) + const tests = await plugin.tests() + const templates = await plugin.templates() + const name = `${plugin.icon} plugins/${plugin.id}` + if (!tests.length) { + Deno.test.ignore(name, () => void null) + continue + } + for (const test of tests) { + Deno.test(`${name} | ${test.name}`, await getPermissions(test), async (t) => { + const { teardown } = setup() + for (const template of templates) { + await t.step(template, async () => { + await expect(process(deepMerge({ presets: { default: { plugins: { template } } } }, deepMerge(config, test, { arrays: "replace" })))).to.be.fulfilled.and.eventually.be.ok + }) + } + teardown() + }) + } +} diff --git a/source/metrics/engine/components/processor.ts b/source/metrics/engine/components/processor.ts index cc80ee83bd1..2540a34ab62 100644 --- a/source/metrics/engine/components/processor.ts +++ b/source/metrics/engine/components/processor.ts @@ -4,6 +4,7 @@ import { processor as schema } from "@engine/config.ts" import { list } from "@utils/io.ts" import type { Plugin } from "@engine/components/plugin.ts" import { Requests } from "@engine/components/requests.ts" +import { throws } from "@utils/errors.ts" /** Processor */ export abstract class Processor extends Component { @@ -29,8 +30,11 @@ export abstract class Processor extends Component { readonly outputs = is.object({}) /** Is supported ? */ - protected supported() { - //TODO(@lowlighter): Implement + protected async supported(state: state) { + const { mime } = await this.piped(state) + if ((this.supports.length) && (!this.supports.includes(mime))) { + throws(`${this.id} not supported for ${mime}`) + } } /** Retrieve piped result */ diff --git a/source/metrics/engine/components/processor_test.ts b/source/metrics/engine/components/processor_test.ts new file mode 100644 index 00000000000..d4dbc6d82bb --- /dev/null +++ b/source/metrics/engine/components/processor_test.ts @@ -0,0 +1,60 @@ +import { expect, MetricsError, test } from "@utils/testing.ts" +import { Processor } from "@engine/components/processor.ts" +import { config as schema } from "@engine/config.ts" +import { config, getPermissions, setup } from "@engine/components/component_test.ts" +import { deepMerge } from "std/collections/deep_merge.ts" +import { process } from "@engine/process.ts" +//import * as dir from "@engine/paths.ts" + +// TODO(@lowlighter): change to `[dir.source]` after https://github.com/denoland/deno_std/pull/3692 +Deno.test("Processor()", { permissions: { read: true } }, async (t) => { + const { plugins: [{ processors: [context] }] } = schema.parse({ plugins: [{ processors: [{ id: "test", logs: "none", fatal: true, retries: { delay: 0 } }] }] }) as test + class TestProcessor extends Processor { + static readonly meta = { url: "test" } as test + readonly name = "⚗️ Test processor" + readonly category = "testing" + readonly supports = ["image/svg+xml"] + readonly description = "Test processor" + protected async action() {} + async run({ mime }: test) { + const state = await Processor.state.parseAsync({ result: { content: "", mime, base64: false, result: {} }, results: [], errors: [] }) + return super.run(state) + } + constructor(context: Processor["context"]) { + super(context) + } + } + + await t.step("tests() returns a list of tests", async () => { + const plugin = new TestProcessor(context) + await expect(plugin.tests()).to.eventually.be.an("array") + }) + + await t.step("supported()", async (t) => { + await t.step("is a noop when entity is supported", async () => { + const plugin = new TestProcessor(context) + await expect(plugin.run({ mime: "image/svg+xml" })).to.be.eventually.be.ok + }) + await t.step("throws if not supported", async () => { + const plugin = new TestProcessor(context) + await expect(plugin.run({ mime: "text/plain" })).to.be.rejectedWith(MetricsError, /not supported for text\/plain/i) + }) + }) +}) + +for (const id of await Processor.list()) { + const processor = await Processor.load({ id }) + const tests = await processor.tests() + const name = `${processor.icon} processors/${processor.id}` + if (!tests.length) { + Deno.test.ignore(name, () => void null) + continue + } + for (const test of tests) { + Deno.test(`${name} | ${test.name}`, await getPermissions(test), async () => { + const { teardown } = setup() + await expect(process(deepMerge(config, test, { arrays: "replace" }))).to.be.fulfilled.and.eventually.be.ok + teardown() + }) + } +} diff --git a/source/metrics/engine/components/requests.ts b/source/metrics/engine/components/requests.ts index d3645f7436c..d72689243c4 100644 --- a/source/metrics/engine/components/requests.ts +++ b/source/metrics/engine/components/requests.ts @@ -109,7 +109,7 @@ export class Requests extends Internal { /** Ratelimit */ async ratelimit() { - const { data: { resources: { core, search, graphql = { remaining: 0, limit: 0 }, ...others } } } = await this.octokit.rest.rateLimit.get() + const { data: { resources: { core, search, graphql = { remaining: 0, limit: 0 }, ...others } } } = await this.rest(this.api.rateLimit.get) const { code_search: code } = others as { code_search: { remaining: number; limit: number } } this.log.io({ core: `${core.remaining}/${core.limit}`, diff --git a/source/metrics/engine/components/requests_test.ts b/source/metrics/engine/components/requests_test.ts new file mode 100644 index 00000000000..67a2c572e2f --- /dev/null +++ b/source/metrics/engine/components/requests_test.ts @@ -0,0 +1,63 @@ +import { Requests } from "@engine/components/requests.ts" +import { expect, Status } from "@utils/testing.ts" +import { Secret } from "@utils/secret.ts" +import * as dir from "@engine/paths.ts" + +Deno.test("Requests()", { permissions: { read: [dir.source] } }, async (t) => { + const requests = new Requests(import.meta, { logs: "none", mock: true, api: "https://api.github.com", timezone: "Europe/Paris", token: new Secret(null) }) + + await t.step("rest()", async (t) => { + await t.step("mocks responses when mock is enabled", async () => { + await expect(requests.rest(requests.api.meta.getOctocat)).to.be.eventually.containSubset({ status: Status.OK }).and.to.include.keys("data") + }) + await t.step("fallbacks on net if mocks are missing when mock is enabled", async () => { + await expect(requests.rest(requests.api.meta.getZen)).to.be.rejectedWith(Error, /requires net access/i) + await expect(requests.rest(requests.api.meta.root)).to.be.rejectedWith(Error, /requires net access/i) + }) + await t.step("handles paginated responses", async () => { + await expect(requests.rest(requests.api.meta.root, {}, { paginate: true })).to.be.rejectedWith(Error, /requires net access/i) + }) + }) + + await t.step("graphql()", async (t) => { + await t.step("mocks responses when mock is enabled", async () => { + await expect(requests.graphql("../tests/mock", { foo: true })).to.be.eventually.deep.equal({ bar: true }) + }) + await t.step("fallbacks on net if mocks are missing when mock is enabled", async () => { + await expect(requests.graphql("../tests/mock_missing", { foo: true })).to.be.rejectedWith(Error, /requires net access/i) + }) + await t.step("handles paginated responses", async (t) => { + await t.step("iterates over cursors", async () => { + await expect(requests.graphql("../tests/mock_paginate", { foo: true }, { paginate: true })).to.be.rejectedWith(Error, /requires net access/i) + }) + await t.step("throws for requests without pagination", async () => { + await expect(requests.graphql("../tests/mock_paginate_bad", { foo: true }, { paginate: true })).to.be.rejectedWith(Error, /missing "pageInfo.*" but pagination is enabled/i) + }) + }) + }) + + await t.step("fetch()", async (t) => { + await t.step('mocks responses for ".test" domains when mock is enabled', async () => { + await expect(requests.fetch("https://metrics.test/mock")).to.be.eventually.equal("foo") + }) + await t.step("fallbacks on net if mocks are missing when mock is enabled", async () => { + await expect(requests.fetch("https://metrics.test/mock_missing")).to.be.rejectedWith(Error, /requires net access/i) + }) + await t.step("returns plain text when asked", async () => { + await expect(requests.fetch(`data:text/plain;base64,${btoa("foo")}`, { type: "text" })).to.eventually.equal("foo") + }) + await t.step("returns parsed json when asked", async () => { + await expect(requests.fetch(`data:application/json;base64,${btoa('{"foo":true}')}`, { type: "json" })).to.eventually.deep.equal({ foo: true }) + }) + await t.step("returns response when asked", async () => { + const fetched = requests.fetch(`data:text/plain;base64,${btoa("foo")}`, { type: "response" }) + await expect(fetched).to.eventually.be.instanceof(Response) + const response = await fetched + response.body?.cancel() + }) + }) + + await t.step("ratelimit() returns remaining requests", async () => { + await expect(requests.ratelimit()).to.eventually.include.keys("core", "graphql", "search", "code") + }) +}) diff --git a/source/metrics/engine/components/tests/mock.graphql b/source/metrics/engine/components/tests/mock.graphql new file mode 100644 index 00000000000..0fcc09ff1ed --- /dev/null +++ b/source/metrics/engine/components/tests/mock.graphql @@ -0,0 +1,3 @@ +query Test($foo: Boolean!) { + bar +} diff --git a/source/metrics/engine/components/tests/mock.graphql.ts b/source/metrics/engine/components/tests/mock.graphql.ts new file mode 100644 index 00000000000..353ddff9fd6 --- /dev/null +++ b/source/metrics/engine/components/tests/mock.graphql.ts @@ -0,0 +1,5 @@ +import { is, mock } from "@utils/testing.ts" + +export default mock({ foo: is.boolean() }, ({ foo }) => ({ + bar: foo, +})) diff --git a/source/metrics/engine/components/tests/mock.http.ts b/source/metrics/engine/components/tests/mock.http.ts new file mode 100644 index 00000000000..18e701947e8 --- /dev/null +++ b/source/metrics/engine/components/tests/mock.http.ts @@ -0,0 +1,5 @@ +import { mock } from "@utils/testing.ts" + +export default mock({}, () => { + return "foo" +}) diff --git a/source/metrics/engine/components/tests/mock_missing.graphql b/source/metrics/engine/components/tests/mock_missing.graphql new file mode 100644 index 00000000000..0fcc09ff1ed --- /dev/null +++ b/source/metrics/engine/components/tests/mock_missing.graphql @@ -0,0 +1,3 @@ +query Test($foo: Boolean!) { + bar +} diff --git a/source/metrics/engine/components/tests/mock_paginate.graphql b/source/metrics/engine/components/tests/mock_paginate.graphql new file mode 100644 index 00000000000..2ed5f52f42e --- /dev/null +++ b/source/metrics/engine/components/tests/mock_paginate.graphql @@ -0,0 +1,11 @@ +query Test($foo: Boolean!, $cursor: String) { + bar(after: $cursor) { + nodes { + value + } + pageInfo { + hasNextPage + endCursor + } + } +} diff --git a/source/metrics/engine/components/tests/mock_paginate_bad.graphql b/source/metrics/engine/components/tests/mock_paginate_bad.graphql new file mode 100644 index 00000000000..46f02b0eaf0 --- /dev/null +++ b/source/metrics/engine/components/tests/mock_paginate_bad.graphql @@ -0,0 +1,7 @@ +query Test($foo: Boolean!, $cursor: String) { + bar(after: $cursor) { + nodes { + value + } + } +} diff --git a/source/metrics/engine/components/tests/rest.ts b/source/metrics/engine/components/tests/rest.ts new file mode 100644 index 00000000000..9c52918350b --- /dev/null +++ b/source/metrics/engine/components/tests/rest.ts @@ -0,0 +1,42 @@ +import { mock, Status } from "@utils/testing.ts" +import { throws } from "@utils/errors.ts" + +export default { + "/octocat": mock({}, () => ({ + status: Status.OK, + data: new TextEncoder().encode(` + MMM. .MMM + MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMMMMMMM _________________________________________ + MMMMMMMMMMMMMMMMMMMMM | | + MMMMMMMMMMMMMMMMMMMMMMM | Anything added dilutes everything else. | + MMMMMMMMMMMMMMMMMMMMMMMM |_ _____________________________________| + MMMM::- -:::::::- -::MMMM |/ + MM~:~ 00~:::::~ 00~:~MM +.. MMMMM::.00:::+:::.00::MMMMM .. + .MM::::: ._. :::::MM. + MMMM;:::::;MMMM + -MM MMMMMMM + ^ M+ MMMMMMMMM + MMMMMMM MM MM MM + MM MM MM MM + MM MM MM MM + .~~MM~MM~MM~MM~~. + ~~~~MM:~MM~~~MM~:MM~~~~ + ~~~~~~==~==~~~==~==~~~~~~ + ~~~~~~==~==~==~==~~~~~~ + :~==~==~==~==~~`), + })), + "/zen": () => throws("Expected error"), + "/rate_limit": mock({}, () => ({ + status: Status.OK, + data: { + resources: { + core: { remaining: 0, limit: 0 }, + search: { remaining: 0, limit: 0 }, + graphql: { remaining: 0, limit: 0 }, + code_search: { remaining: 0, limit: 0 }, + }, + }, + })), +} diff --git a/source/metrics/utils/browser.ts b/source/metrics/utils/browser.ts index 3f9f0bdcf7d..b05eff12437 100644 --- a/source/metrics/utils/browser.ts +++ b/source/metrics/utils/browser.ts @@ -1,6 +1,6 @@ //Imports import { Logger } from "@utils/log.ts" -import { getBinary, launch } from "gh/lowlighter/astral@fix-dont-require-env-perms-with-cache/mod.ts" // TODO(@lowlighter): use astral@main when available +import { getBinary, launch } from "gh/lino-levan/astral@main/mod.ts" // TODO(@lowlighter): use x/astral when available import { env } from "@utils/io.ts" import { cache } from "@engine/paths.ts" import { throws } from "@utils/errors.ts" diff --git a/source/plugins/calendar/tests/list.yml b/source/plugins/calendar/tests/list.yml index a6555b6f60a..1ccc27cf967 100644 --- a/source/plugins/calendar/tests/list.yml +++ b/source/plugins/calendar/tests/list.yml @@ -8,12 +8,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .year .day - count: 180~1 + html: + select: .calendar .year .day + count: 180~1 - id: calendar handle: octocat args: @@ -22,12 +24,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .year .day - count: 180~1 + html: + select: .calendar .year .day + count: 180~1 - name: range last-365-days plugins: @@ -39,12 +43,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .year .day - count: 365~1 + html: + select: .calendar .year .day + count: 365~1 - id: calendar handle: octocat args: @@ -53,12 +59,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .year .day - count: 365~1 + html: + select: .calendar .year .day + count: 365~1 - name: range current-year plugins: @@ -69,12 +77,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .title sub - match: /1 jan (\d+) to \d+ \w+ \1/i + html: + select: .calendar .title sub + match: /1 jan (\d+) to \d+ \w+ \1/i - name: range specific year plugins: @@ -85,12 +95,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .title sub - match: /1 jan 2020 to 31 dec 2020/i + html: + select: .calendar .title sub + match: /1 jan 2020 to 31 dec 2020/i - id: calendar handle: octocat args: @@ -98,12 +110,14 @@ processors: - id: assert args: - select: .calendar .year - count: 1= + html: + select: .calendar .year + count: 1= - id: assert args: - select: .calendar .title sub - match: /1 jan 1970 to 31 dec 1970/i + html: + select: .calendar .title sub + match: /1 jan 1970 to 31 dec 1970/i - name: range specific years plugins: @@ -116,12 +130,14 @@ processors: - id: assert args: - select: .calendar .year - count: 2= + html: + select: .calendar .year + count: 2= - id: assert args: - select: .calendar .title sub - match: /1 jan 2019 to 31 dec 2020/i + html: + select: .calendar .title sub + match: /1 jan 2019 to 31 dec 2020/i - name: range relative years plugins: @@ -134,8 +150,9 @@ processors: - id: assert args: - select: .calendar .year - count: 2= + html: + select: .calendar .year + count: 2= - id: calendar handle: octocat args: @@ -145,12 +162,14 @@ processors: - id: assert args: - select: .calendar .year - count: 2= + html: + select: .calendar .year + count: 2= - id: assert args: - select: .calendar .title sub - match: /1 jan 2019 to 31 dec 2020/i + html: + select: .calendar .title sub + match: /1 jan 2019 to 31 dec 2020/i - name: range from registration plugins: @@ -163,8 +182,9 @@ processors: - id: assert args: - select: .calendar .year - count: 1>= + html: + select: .calendar .year + count: 1>= - name: color schemes plugins: @@ -176,9 +196,10 @@ processors: - id: assert args: - select: .calendar svg.render [fill^="var"] - match: /fill="var\(--calendar-halloween-L\d\)"/ - html: true + html: + select: .calendar svg.render [fill^="var"] + match: /fill="var\(--calendar-halloween-L\d\)"/ + raw: true - id: calendar handle: octocat args: @@ -187,6 +208,7 @@ processors: - id: assert args: - select: .calendar svg.render [fill^="var"] - match: /fill="var\(--calendar-winter-L\d\)"/ - html: true + html: + select: .calendar svg.render [fill^="var"] + match: /fill="var\(--calendar-winter-L\d\)"/ + raw: true diff --git a/source/plugins/gists/tests/list.yml b/source/plugins/gists/tests/list.yml index 9a79f22fd76..4771a273143 100644 --- a/source/plugins/gists/tests/list.yml +++ b/source/plugins/gists/tests/list.yml @@ -8,8 +8,9 @@ processors: - id: assert args: - select: .gists .title - match: /10 gists/i + html: + select: .gists .title + match: /10 gists/i - id: gists handle: octocat entity: user @@ -18,8 +19,9 @@ processors: - id: assert args: - select: .gists .title - match: /20 gists/i + html: + select: .gists .title + match: /20 gists/i - name: gists forks plugins: @@ -31,8 +33,9 @@ processors: - id: assert args: - select: .gists .title - match: /including \d+ forks?/i + html: + select: .gists .title + match: /including \d+ forks?/i - id: gists handle: octocat entity: user @@ -41,6 +44,7 @@ processors: - id: assert args: - select: .gists .title - match: /!/including \d+ forks?/i + html: + select: .gists .title + match: /!/including \d+ forks?/i diff --git a/source/plugins/introduction/tests/list.yml b/source/plugins/introduction/tests/list.yml index c229fc69965..c0d37367ae0 100644 --- a/source/plugins/introduction/tests/list.yml +++ b/source/plugins/introduction/tests/list.yml @@ -6,8 +6,9 @@ processors: - id: assert args: - select: .introduction .text - match: octocat + html: + select: .introduction .text + match: octocat - name: organization plugins: @@ -17,8 +18,9 @@ processors: - id: assert args: - select: .introduction .text - match: github + html: + select: .introduction .text + match: github - name: repository plugins: @@ -28,5 +30,6 @@ processors: - id: assert args: - select: .introduction .text - match: octocat/hello-world \ No newline at end of file + html: + select: .introduction .text + match: octocat/hello-world \ No newline at end of file diff --git a/source/plugins/lines/tests/list.yml b/source/plugins/lines/tests/list.yml index 8a56e486521..e3a9856c071 100644 --- a/source/plugins/lines/tests/list.yml +++ b/source/plugins/lines/tests/list.yml @@ -9,12 +9,14 @@ processors: - id: assert args: - select: .lines .entry .repo - match: octocat/public-repo + html: + select: .lines .entry .repo + match: octocat/public-repo - id: assert args: - select: .lines .entry .repo - match: /!/(user|org)\// + html: + select: .lines .entry .repo + match: /!/(user|org)\// - id: lines handle: octocat entity: user @@ -24,12 +26,14 @@ processors: - id: assert args: - select: .lines .entry .repo - match: user/public-repo + html: + select: .lines .entry .repo + match: user/public-repo - id: assert args: - select: .lines .entry .repo - match: /!/(octocat|org)\// + html: + select: .lines .entry .repo + match: /!/(octocat|org)\// - id: lines handle: octocat entity: user @@ -39,12 +43,14 @@ processors: - id: assert args: - select: .lines .entry .repo - match: org/public-repo + html: + select: .lines .entry .repo + match: org/public-repo - id: assert args: - select: .lines .entry .repo - match: /!/(octocat|user)\// + html: + select: .lines .entry .repo + match: /!/(octocat|user)\// - id: lines handle: octocat entity: user @@ -54,8 +60,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /(octocat|user|org)\/public-repo/ + html: + select: .lines .entry .repo + match: /(octocat|user|org)\/public-repo/ - name: repository visibility plugins: @@ -68,8 +75,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /(public|private)-repo/ + html: + select: .lines .entry .repo + match: /(public|private)-repo/ - id: lines handle: octocat entity: user @@ -79,8 +87,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /!/private-repo/ + html: + select: .lines .entry .repo + match: /!/private-repo/ - name: repository archived plugins: @@ -93,8 +102,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /(?:archived-repo)?/ + html: + select: .lines .entry .repo + match: /(?:archived-repo)?/ - id: lines handle: octocat entity: user @@ -104,8 +114,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /!/archived-repo/ + html: + select: .lines .entry .repo + match: /!/archived-repo/ - name: repository forked plugins: @@ -118,8 +129,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /(?:forked-repo)?/ + html: + select: .lines .entry .repo + match: /(?:forked-repo)?/ - id: lines handle: octocat entity: user @@ -129,8 +141,9 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /!/forked-repo/ + html: + select: .lines .entry .repo + match: /!/forked-repo/ - name: repository matching plugins: @@ -144,12 +157,14 @@ processors: - id: assert args: - select: .lines .entry .repo - match: /octocat\// + html: + select: .lines .entry .repo + match: /octocat\// - id: assert args: - select: .lines .entry .repo - match: /!/(user|org)\// + html: + select: .lines .entry .repo + match: /!/(user|org)\// - name: history limit plugins: @@ -162,8 +177,9 @@ processors: - id: assert args: - select: .lines .entry .week - match: /(2023|2022)/ + html: + select: .lines .entry .week + match: /(2023|2022)/ - id: lines handle: octocat entity: user @@ -173,8 +189,9 @@ processors: - id: assert args: - select: .lines .entry .week - match: /2023/ + html: + select: .lines .entry .week + match: /2023/ - name: empty repository plugins: @@ -184,8 +201,9 @@ processors: - id: assert args: - select: .lines .entry - count: 1= + html: + select: .lines .entry + count: 1= - name: fetching retry plugins: @@ -199,8 +217,9 @@ processors: - id: assert args: - select: .lines .entry - count: 1= + html: + select: .lines .entry + count: 1= - processors: - id: control.delay args: @@ -215,8 +234,9 @@ processors: - id: assert args: - select: .lines .entry - count: 0= + html: + select: .lines .entry + count: 0= - processors: - id: control.delay args: diff --git a/source/plugins/rss/tests/list.yml b/source/plugins/rss/tests/list.yml index 8474b3ec79b..35d01186e6a 100644 --- a/source/plugins/rss/tests/list.yml +++ b/source/plugins/rss/tests/list.yml @@ -7,8 +7,9 @@ processors: - id: assert args: - select: .rss .entry - count: 1= + html: + select: .rss .entry + count: 1= - name: feed with limit disabled plugins: @@ -19,5 +20,6 @@ processors: - id: assert args: - select: .rss .entry - count: 1>= + html: + select: .rss .entry + count: 1>= diff --git a/source/plugins/webscraping/tests/list.yml b/source/plugins/webscraping/tests/list.yml index 32042ca8d51..ad65c04927f 100644 --- a/source/plugins/webscraping/tests/list.yml +++ b/source/plugins/webscraping/tests/list.yml @@ -8,12 +8,14 @@ processors: - id: assert args: - select: .webscraping .title - match: example + html: + select: .webscraping .title + match: example - id: assert args: - select: .webscraping img - count: 1= + html: + select: .webscraping img + count: 1= - name: scrap text plugins: @@ -26,12 +28,14 @@ processors: - id: assert args: - select: .webscraping .title - match: example + html: + select: .webscraping .title + match: example - id: assert args: - select: .webscraping - match: hello world + html: + select: .webscraping + match: hello world - name: error plugins: @@ -43,5 +47,4 @@ processors: - id: assert args: - select: .webscraping error: true diff --git a/source/processors/assert/mod.ts b/source/processors/assert/mod.ts index 84adb498439..2057a8c348f 100644 --- a/source/processors/assert/mod.ts +++ b/source/processors/assert/mod.ts @@ -3,6 +3,7 @@ import { DOMParser } from "x/deno_dom@v0.1.38/deno-dom-wasm.ts" import { Format } from "@utils/format.ts" import { is, Processor, state } from "@engine/components/processor.ts" import { expect } from "@utils/testing.ts" +import { throws } from "@utils/errors.ts" /** Regexs */ const regexs = { @@ -25,22 +26,24 @@ export default class extends Processor { readonly description = "Assert selection matches specified criteria" /** Supports */ - readonly supports = ["application/xml", "image/svg+xml"] + readonly supports = [] /** Inputs */ readonly inputs = is.object({ - select: is.string().default("main").describe("Query selector"), - match: is.coerce.string().optional().describe("Assert element content match pattern (will be treated as regex if matching `/pattern/flags`, prefix with `/!` to negate regex matching)"), - html: is.boolean().default(false).describe("Use raw HTML instead of text content"), - count: is.coerce.string().regex(regexs.count).optional().describe("Assert number of elements"), error: is.boolean().default(false).describe("Assert previous content returned an error"), mime: is.string().optional(), + html: is.object({ + select: is.string().default("main").describe("Query selector"), + match: is.coerce.string().optional().describe("Assert element content match pattern (will be treated as regex if matching `/pattern/flags`, prefix with `/!` to negate regex matching)"), + raw: is.boolean().default(false).describe("Use raw HTML instead of text content"), + count: is.coerce.string().regex(regexs.count).optional().describe("Assert number of elements"), + }).nullable().default(null).describe("HTML selection (mime must be either `application/xml`, `image/svg+xml` or `text/html`)"), }) /** Action */ protected async action(state: state) { const result = await this.piped(state) - const { count, select, match, error, html, mime } = await this.inputs.parseAsync(this.context.args) + const { error, html, mime } = await this.inputs.parseAsync(this.context.args) if (typeof result.content !== "string") { if (error) { return @@ -50,6 +53,16 @@ export default class extends Processor { if (mime) { expect(result.mime).to.include(mime) } + if (!/(application\/xml)|(image\/svg\+xml)|(text\/html)/.test(result.mime)) { + if (html) { + throws(`html selection is only supported for mime type "application/xml", "image/svg+xml" or "text/html" (got "${result.mime}")`) + } + return + } + if (!html) { + return + } + const { select, match, raw, count } = html const document = new DOMParser().parseFromString(Format.html(result.content), "text/html") const selected = [...document?.querySelectorAll(select) ?? []] if (typeof count === "string") { @@ -85,7 +98,7 @@ export default class extends Processor { for (const element of selected) { if (typeof match === "string") { - const content = html ? ((element.parentElement ?? element) as unknown as { innerHTML?: string }).innerHTML ?? "" : element.textContent + const content = raw ? ((element.parentElement ?? element) as unknown as { innerHTML?: string }).innerHTML ?? "" : element.textContent if (regexs.match.test(match)) { const { negate = "", pattern = "", flags = "" } = match.match(regexs.match)!.groups ?? {} const regex = new RegExp(pattern, flags) diff --git a/source/processors/assert/tests/list.yml b/source/processors/assert/tests/list.yml index d622f272911..3e79de344c4 100644 --- a/source/processors/assert/tests/list.yml +++ b/source/processors/assert/tests/list.yml @@ -6,16 +6,19 @@ content: hello world - id: assert args: - select: .test - match: hello world + html: + select: .test + match: hello world - id: assert args: - select: .test - match: /hello world/ + html: + select: .test + match: /hello world/ - id: assert args: - select: .test - match: /!/foo bar/ + html: + select: .test + match: /!/foo bar/ - name: match html plugins: @@ -25,9 +28,10 @@ content: - id: assert args: - select: .test - match: /data-test="true"/ - html: true + html: + select: .test + match: /data-test="true"/ + raw: true - name: count elements plugins: @@ -37,25 +41,31 @@ content: - id: assert args: - select: .a - count: 1= + html: + select: .a + count: 1= - id: assert args: - select: .a - count: 0~1 + html: + select: .a + count: 0~1 - id: assert args: - select: .a - count: 1>= + html: + select: .a + count: 1>= - id: assert args: - select: .a - count: 0> + html: + select: .a + count: 0> - id: assert args: - select: .a - count: 1<= + html: + select: .a + count: 1<= - id: assert args: - select: .a - count: 2< + html: + select: .a + count: 2< diff --git a/source/processors/inject.content/mod.ts b/source/processors/inject.content/mod.ts index bfc8837951f..18854b38488 100644 --- a/source/processors/inject.content/mod.ts +++ b/source/processors/inject.content/mod.ts @@ -21,12 +21,16 @@ export default class extends Processor { /** Inputs */ readonly inputs = is.object({ content: is.string().describe("Content to inject"), + mime: is.string().optional().describe("Resulting mime type"), }) /** Action */ protected async action(state: state) { const result = await this.piped(state) - const { content } = await this.inputs.parseAsync(this.context.args) + const { content, mime } = await this.inputs.parseAsync(this.context.args) + if (mime) { + result.mime = mime + } result.content = `${result.content}${content}` } } diff --git a/source/processors/inject.content/tests/list.yml b/source/processors/inject.content/tests/list.yml index 75135313f0c..e3ac6933f9a 100644 --- a/source/processors/inject.content/tests/list.yml +++ b/source/processors/inject.content/tests/list.yml @@ -6,5 +6,17 @@ content: hello world - id: assert args: - select: main - match: hello world + html: + select: main + match: hello world + +- name: mime + plugins: + - processors: + - id: inject.content + args: + content: hello world + mime: text/plain + - id: assert + args: + mime: text/plain \ No newline at end of file diff --git a/source/processors/inject.script/tests/list.yml b/source/processors/inject.script/tests/list.yml index 7b450563f3a..620c7e1123f 100644 --- a/source/processors/inject.script/tests/list.yml +++ b/source/processors/inject.script/tests/list.yml @@ -10,8 +10,9 @@ document.querySelector(".test").textContent = "hello world"; - id: assert args: - select: .test - match: hello world + html: + select: .test + match: hello world - name: inject error plugins: diff --git a/source/processors/inject.style/tests/list.yml b/source/processors/inject.style/tests/list.yml index b211c3db7e4..1c7c410f19e 100644 --- a/source/processors/inject.style/tests/list.yml +++ b/source/processors/inject.style/tests/list.yml @@ -10,11 +10,13 @@ .test { color: blue; } - id: assert args: - select: .test - match: //i - html: true + html: + select: .test + match: //i + raw: true - id: assert args: - select: .test - match: /\[inject-style-.*?\]\s+.test.*color:\s+blue/i - html: true + html: + select: .test + match: /\[inject-style-.*?\]\s+.test.*color:\s+blue/i + raw: true diff --git a/source/processors/optimize.css/tests/list.yml b/source/processors/optimize.css/tests/list.yml index b50e51a15d4..1ebb387cb31 100644 --- a/source/processors/optimize.css/tests/list.yml +++ b/source/processors/optimize.css/tests/list.yml @@ -17,12 +17,14 @@ - id: optimize.css - id: assert args: - select: svg style - match: /\.a\{.*\}/i + html: + select: svg style + match: /\.a\{.*\}/i - id: assert args: - select: svg style - match: /!/\.b\{.*\}/i + html: + select: svg style + match: /!/\.b\{.*\}/i - name: optimize does not remove non-optimizable styles plugins: @@ -43,9 +45,11 @@ - id: optimize.css - id: assert args: - select: svg style - match: /\.a { color:\ red; \}/i + html: + select: svg style + match: /\.a { color:\ red; \}/i - id: assert args: - select: svg style - match: /\.b \{ color:\ blue; \}/i + html: + select: svg style + match: /\.b \{ color:\ blue; \}/i diff --git a/source/processors/optimize.svg/tests/list.yml b/source/processors/optimize.svg/tests/list.yml index 877963a89d0..8cce73a35af 100644 --- a/source/processors/optimize.svg/tests/list.yml +++ b/source/processors/optimize.svg/tests/list.yml @@ -4,12 +4,14 @@ - id: inject.content args: content: + mime: image/svg+xml - id: optimize.svg - id: assert args: - select: main - match: /<.svg>/i - html: true + html: + select: main + match: /<.svg>/i + raw: true - name: invalid svg plugins: @@ -17,6 +19,7 @@ - id: inject.content args: content: + mime: image/svg+xml - id: optimize.svg fatal: false - id: assert diff --git a/source/processors/optimize.xml/tests/list.yml b/source/processors/optimize.xml/tests/list.yml index 00e71f3a5d9..c2a7469f87c 100644 --- a/source/processors/optimize.xml/tests/list.yml +++ b/source/processors/optimize.xml/tests/list.yml @@ -7,9 +7,10 @@ - id: optimize.xml - id: assert args: - select: main - match: /<.span>/i - html: true + html: + select: main + match: /<.span>/i + raw: true - name: invalid svg plugins: diff --git a/source/processors/render.gemojis/tests/list.yml b/source/processors/render.gemojis/tests/list.yml index 64fbf0e1766..571d5508655 100644 --- a/source/processors/render.gemojis/tests/list.yml +++ b/source/processors/render.gemojis/tests/list.yml @@ -7,8 +7,9 @@ - id: render.gemojis - id: assert args: - select: img.gemoji - count: 1= + html: + select: img.gemoji + count: 1= - name: invalid emoji plugins: @@ -19,6 +20,7 @@ - id: render.gemojis - id: assert args: - select: img.gemoji - count: 0= - match: ":__invalid__:" + html: + select: img.gemoji + count: 0= + match: ":__invalid__:" diff --git a/source/processors/render.octicons/tests/list.yml b/source/processors/render.octicons/tests/list.yml index e0e58b8db88..b930f764cbf 100644 --- a/source/processors/render.octicons/tests/list.yml +++ b/source/processors/render.octicons/tests/list.yml @@ -7,10 +7,11 @@ - id: render.octicons - id: assert args: - select: svg.octicon - count: 1= - match: height="16" - html: true + html: + select: svg.octicon + count: 1= + match: height="16" + raw: true - name: render with size plugins: @@ -21,10 +22,11 @@ - id: render.octicons - id: assert args: - select: svg.octicon - count: 1= - match: height="24" - html: true + html: + select: svg.octicon + count: 1= + match: height="24" + raw: true - name: invalid octicon plugins: @@ -35,6 +37,7 @@ - id: render.octicons - id: assert args: - select: svg.octicon - count: 0= - match: ":octicon-__invalid__:" + html: + select: svg.octicon + count: 0= + match: ":octicon-__invalid__:" diff --git a/source/processors/render.twemojis/tests/list.yml b/source/processors/render.twemojis/tests/list.yml index 47e5fb39578..d0567925314 100644 --- a/source/processors/render.twemojis/tests/list.yml +++ b/source/processors/render.twemojis/tests/list.yml @@ -7,5 +7,6 @@ - id: render.twemojis - id: assert args: - select: svg.twemoji - count: 1= + html: + select: svg.twemoji + count: 1= diff --git a/source/processors/render/tests/list.yml b/source/processors/render/tests/list.yml index 585da9a188d..c4af3efb922 100644 --- a/source/processors/render/tests/list.yml +++ b/source/processors/render/tests/list.yml @@ -9,8 +9,9 @@ format: svg - id: assert args: - match: /.*hello world.*<.svg>/is - html: true + html: + match: /.*hello world.*<.svg>/is + raw: true mime: image/svg+xml - name: render png @@ -68,13 +69,15 @@ - id: inject.content args: content: hello world + - id: render args: format: html - id: assert args: - match: /.*?<.title>/is - html: true + html: + match: /<title>.*?<.title>/is + raw: true mime: text/html - name: render json @@ -88,6 +91,4 @@ format: json - id: assert args: - match: /\{"results":.*,"errors":.*\}/is - html: true mime: application/json diff --git a/source/run/cli/mod.ts b/source/run/cli/mod.ts index a85a53e4f76..faddecaba76 100644 --- a/source/run/cli/mod.ts +++ b/source/run/cli/mod.ts @@ -7,7 +7,6 @@ import core from "y/@actions/core@1.10.1" import { process } from "@engine/process.ts" import { parse } from "std/flags/mod.ts" import { cyan, gray } from "std/fmt/colors.ts" -import { expandGlobSync } from "std/fs/expand_glob.ts" import { env } from "@utils/io.ts" import { compat } from "./compat.ts" @@ -22,11 +21,13 @@ class CLI extends Internal { /** Constructor */ constructor(context = {} as Record<PropertyKey, unknown>) { super(schema.parse(context)) - this.setup() } - /** General setup */ - private setup() { + /** Run metrics */ + async run() { + this.log.info(`Metrics ${version}`) + this.log.probe(github.context) + this.log.probe(Deno.env.toObject()) // GitHub action setup if ((env.actions) && (env.get("INPUTS"))) { const inputs = JSON.parse(env.get("INPUTS")!) as Record<PropertyKey, unknown> @@ -35,24 +36,14 @@ class CLI extends Internal { } console.log(compat(inputs)) } - } - - /** Run metrics */ - async run() { - this.log.info(`Metrics ${version}`) - this.log.probe(github.context) - this.log.probe(Deno.env.toObject()) - try { - this.log.probe([...expandGlobSync("**/*.md", { root: "/workspace" })].filter(({ isDirectory }) => isDirectory).map(({ path }) => path)) - } catch (error) { - console.log(error) - } + // Check for updates if (this.context.check_updates) { const upstream = await latest() if (version.number !== upstream) { core.info(`Version ${upstream} is available!`) } } + // await process(this.context.config) }