|
1 | 1 | import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; |
2 | | -import { compileScriptCode, compileScript, compileInjectScript, addStyle, addStyleSheet } from "./utils"; |
| 2 | +import { |
| 3 | + compileScriptCode, |
| 4 | + compileScript, |
| 5 | + compileInjectScript, |
| 6 | + compileScriptletCode, |
| 7 | + isScriptletUnwrap, |
| 8 | + addStyle, |
| 9 | + addStyleSheet, |
| 10 | +} from "./utils"; |
3 | 11 | import type { ScriptRunResource } from "@App/app/repo/scripts"; |
4 | 12 | import type { ScriptFunc } from "./types"; |
| 13 | +import { RuleType, type URLRuleEntry } from "@App/pkg/utils/url_matcher"; |
5 | 14 |
|
6 | 15 | // 设置 console mock 来避免测试输出污染 |
7 | 16 | vi.spyOn(console, "error").mockImplementation(() => {}); |
@@ -518,4 +527,138 @@ describe("utils", () => { |
518 | 527 | expect((returnedSheet as any).cssText).toBe(css); |
519 | 528 | }); |
520 | 529 | }); |
| 530 | + |
| 531 | + describe.concurrent("isScriptletUnwrap", () => { |
| 532 | + it.concurrent("@unwrap 为空值时返回 true", () => { |
| 533 | + expect(isScriptletUnwrap({ unwrap: [""] })).toBe(true); |
| 534 | + }); |
| 535 | + |
| 536 | + it.concurrent("@unwrap 为 true 时返回 true", () => { |
| 537 | + expect(isScriptletUnwrap({ unwrap: ["true"] })).toBe(true); |
| 538 | + }); |
| 539 | + |
| 540 | + it.concurrent("没有 @unwrap 时返回 false", () => { |
| 541 | + expect(isScriptletUnwrap({})).toBe(false); |
| 542 | + }); |
| 543 | + |
| 544 | + it.concurrent("@unwrap 为 false 时返回 false", () => { |
| 545 | + expect(isScriptletUnwrap({ unwrap: ["false"] })).toBe(false); |
| 546 | + }); |
| 547 | + }); |
| 548 | + |
| 549 | + describe.concurrent("compileScriptletCode", () => { |
| 550 | + const createMockScriptRes = ( |
| 551 | + overrides: Partial<ScriptRunResource> = {}, |
| 552 | + scriptUrlPatterns: URLRuleEntry[] = [] |
| 553 | + ): { scriptRes: ScriptRunResource; scriptUrlPatterns: URLRuleEntry[] } => ({ |
| 554 | + scriptRes: { |
| 555 | + uuid: "test-uuid", |
| 556 | + name: "Unwrap Script", |
| 557 | + namespace: "test.namespace", |
| 558 | + type: 1, |
| 559 | + status: 1, |
| 560 | + sort: 0, |
| 561 | + runStatus: "complete", |
| 562 | + createtime: Date.now(), |
| 563 | + checktime: Date.now(), |
| 564 | + code: "console.log('unwrap');", |
| 565 | + value: {}, |
| 566 | + flag: "test-flag", |
| 567 | + resource: {}, |
| 568 | + metadata: { unwrap: [""] }, |
| 569 | + originalMetadata: {}, |
| 570 | + ...overrides, |
| 571 | + }, |
| 572 | + scriptUrlPatterns, |
| 573 | + }); |
| 574 | + |
| 575 | + it.concurrent("应该正确编译基本 unwrap 脚本", () => { |
| 576 | + const patterns: URLRuleEntry[] = [ |
| 577 | + { |
| 578 | + ruleType: RuleType.MATCH_INCLUDE, |
| 579 | + ruleContent: ["https", "example.com", "*"], |
| 580 | + ruleTag: "match", |
| 581 | + patternString: "https://example.com/*", |
| 582 | + }, |
| 583 | + ]; |
| 584 | + const { scriptRes } = createMockScriptRes({}, patterns); |
| 585 | + |
| 586 | + const result = compileScriptletCode(scriptRes, scriptRes.code, patterns); |
| 587 | + |
| 588 | + // 包含脚本代码 |
| 589 | + expect(result).toContain("console.log('unwrap');"); |
| 590 | + // 包含 sourceURL |
| 591 | + expect(result).toContain("sourceURL="); |
| 592 | + expect(chrome.runtime.getURL).toHaveBeenCalledWith("/Unwrap%20Script.user.js"); |
| 593 | + // 包含 flag 注册 |
| 594 | + expect(result).toContain("window['test-flag']=function(){};"); |
| 595 | + // 包含 URL 条件包裹 (if(...){...}) |
| 596 | + expect(result).toMatch(/^if\(/); |
| 597 | + // 不包含沙箱封装 |
| 598 | + expect(result).not.toContain("with(arguments[0]||this.$)"); |
| 599 | + expect(result).not.toContain("return(async function(){"); |
| 600 | + }); |
| 601 | + |
| 602 | + it.concurrent("应该包含 require 资源", () => { |
| 603 | + const patterns: URLRuleEntry[] = [ |
| 604 | + { |
| 605 | + ruleType: RuleType.MATCH_INCLUDE, |
| 606 | + ruleContent: ["*", "example.com", "*"], |
| 607 | + ruleTag: "match", |
| 608 | + patternString: "*://example.com/*", |
| 609 | + }, |
| 610 | + ]; |
| 611 | + const { scriptRes } = createMockScriptRes( |
| 612 | + { |
| 613 | + metadata: { |
| 614 | + unwrap: [""], |
| 615 | + require: ["https://cdn.example.com/lib.js"], |
| 616 | + }, |
| 617 | + resource: { |
| 618 | + "https://cdn.example.com/lib.js": { |
| 619 | + url: "https://cdn.example.com/lib.js", |
| 620 | + content: "var libLoaded = true;", |
| 621 | + base64: "", |
| 622 | + hash: { md5: "t", sha1: "t", sha256: "t", sha384: "t", sha512: "t" }, |
| 623 | + type: "require", |
| 624 | + link: {}, |
| 625 | + contentType: "text/javascript", |
| 626 | + createtime: Date.now(), |
| 627 | + }, |
| 628 | + }, |
| 629 | + }, |
| 630 | + patterns |
| 631 | + ); |
| 632 | + |
| 633 | + const result = compileScriptletCode(scriptRes, scriptRes.code, patterns); |
| 634 | + |
| 635 | + expect(result).toContain("var libLoaded = true;"); |
| 636 | + expect(result).toContain("console.log('unwrap');"); |
| 637 | + }); |
| 638 | + |
| 639 | + it.concurrent("应该包含 URL 条件检查代码", () => { |
| 640 | + const patterns: URLRuleEntry[] = [ |
| 641 | + { |
| 642 | + ruleType: RuleType.MATCH_INCLUDE, |
| 643 | + ruleContent: ["https", "example.com", "*"], |
| 644 | + ruleTag: "match", |
| 645 | + patternString: "https://example.com/*", |
| 646 | + }, |
| 647 | + { |
| 648 | + ruleType: RuleType.MATCH_EXCLUDE, |
| 649 | + ruleContent: ["https", "example.com", "admin/*"], |
| 650 | + ruleTag: "match", |
| 651 | + patternString: "https://example.com/admin/*", |
| 652 | + }, |
| 653 | + ]; |
| 654 | + const { scriptRes } = createMockScriptRes({}, patterns); |
| 655 | + |
| 656 | + const result = compileScriptletCode(scriptRes, scriptRes.code, patterns); |
| 657 | + |
| 658 | + // 生成的代码应包含 embeddedPatternChecker 调用 |
| 659 | + expect(result).toContain("location.href"); |
| 660 | + // if 条件包裹 |
| 661 | + expect(result).toMatch(/^if\(/); |
| 662 | + }); |
| 663 | + }); |
521 | 664 | }); |
0 commit comments