Skip to content

Commit 0e6ee9f

Browse files
DavertMikclaude
andcommitted
test(Obscura): runner-level acceptance suite
test/acceptance/codecept.Obscura.js mirrors codecept.Playwright.js's shape: TestHelper.siteUrl(), Obscura in self-launch mode (no endpoint -- binary resolved via OBSCURA_PATH/PATH, same as the existing helper-suite config), ScreenshotSessionHelper, @codeceptjs/expect-helper, the same bootstrap/ mocha/plugins/gherkin blocks, grep: '@obscura'. Every scenario tagged @obscura was verified empirically against the real runner (./bin/codecept.js run -c test/acceptance/codecept.Obscura.js --grep @obscura, both plain and --debug, run repeatedly for consistency), never guessed. Tagged: the 4 gherkin features already carrying another engine's tag (background/basic/before_hook/examples -- all pass), config_test.js's 6 dynamic-config scenarios + simple page test (the mock-server-dependent "make API call" scenario fails identically for Playwright in this environment -- pre-existing, unrelated), and within_test.js's one scenario that expects an ElementNotFound throw (genuinely correct for Obscura). Left untagged, with root causes found rather than assumed: - els.js's element()/eachElement()/expectElement() family requires ANY helper with a _locate method returning real element handles (lib/els.js:147); CDPBrowser has no such method and doesn't hold element handles at all by design (candidates are re-resolved in-page per call). grabWebElements/CDPElementHandle exist but don't implement the handle interface (.getAttribute/.click/.type/.$/.$$/etc.) els.js's consumers need -- building that out is a real feature, not a small fix, so this contradicts the mandate's "els/grabWebElements expected to work" premise and is reported as such rather than forced. - within_test.js's other 10 scenarios: 9 need switchTo/iframe support CDPBrowser doesn't implement (I.switchTo is not a function -- confirmed hard incompatibility, matches expectation). The remaining one (locate().at().find() scoped inside within(...)) surfaced two distinct, pre-existing framework-level issues, not Obscura-specific, isolated via a minimal standalone repro: (a) lib/effects.js's within() calls _withinBegin via recorder.add() before invoking the within callback -- if _withinBegin itself rejects, the callback's .then/.catch (which is what tears down recorder.session.start('within')) never runs, corrupting the recorder session for every later scenario in the same process; (b) the XPath a chained locate().at(N) produces is absolute ("//...", not ".//...") so document.evaluate(xpath, root, ...) ignores the within scope's root entirely -- a locator-generation issue in core, not this helper. Both live in lib/ and are shared across all helpers; per this mandate's own scope (prefer not touching lib/, fix only small/safe things), neither was fixed here, only diagnosed and reported. - session_test.js: CDPBrowser has no _session (confirmed absent, matching the mandate's own expectation) -- session() throws "Configured helpers do not support starting sessions." But several of its non-async scenarios call session() without awaiting the (async) global wrapper, so the rejection becomes an unhandled promise rejection AFTER the scenario has already moved on, making them show as a false-positive pass with the session's own inner steps silently skipped. Left entirely untagged regardless of the runner's raw pass/fail, since none of them are semantically valid for a _session-less helper. - retryTo_test.js, coverage_test.js, shadow_dom.feature: none carry a tag for any currently-active engine (no @Playwright/@Puppeteer/@webdriverio anywhere in them) -- not part of the established cross-engine comparison this mandate extends, so left alone rather than newly exercised only for Obscura. .github/workflows/obscura.yml gets a new step after the existing unit-test step, running the acceptance config with the same OBSCURA_PATH env (self-launch proves itself again at runner level, as it already does for the unit suite). No lib/ changes. Full @obscura suite: 14 scenarios, 0 failures, run repeatedly (plain and --debug) for consistency, no hang, clean exit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 7f948c7 commit 0e6ee9f

8 files changed

Lines changed: 48 additions & 12 deletions

File tree

.github/workflows/obscura.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,7 @@ jobs:
6666
run: |
6767
export OBSCURA_PATH="$HOME/obscura-bin/obscura"
6868
npm run test:unit:webbapi:obscura
69+
- name: run obscura acceptance tests
70+
run: |
71+
export OBSCURA_PATH="$HOME/obscura-bin/obscura"
72+
./bin/codecept.js run -c test/acceptance/codecept.Obscura.js --grep @Obscura --debug
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import TestHelper from '../support/TestHelper.js'
2+
import installCodeceptjs from '../support/install-codeceptjs.js'
3+
4+
export const config = {
5+
tests: './*_test.js',
6+
timeout: 10,
7+
output: './output',
8+
grep: '@Obscura',
9+
helpers: {
10+
Obscura: {
11+
url: TestHelper.siteUrl(),
12+
},
13+
ScreenshotSessionHelper: {
14+
require: '../support/ScreenshotSessionHelper.js',
15+
outputPath: 'test/acceptance/output',
16+
},
17+
'@codeceptjs/expect-helper': {},
18+
},
19+
include: {},
20+
bootstrap: installCodeceptjs,
21+
mocha: {},
22+
plugins: {
23+
retryFailedStep: {
24+
enabled: true,
25+
},
26+
},
27+
name: 'acceptance',
28+
gherkin: {
29+
features: './gherkin/*.feature',
30+
steps: ['./gherkin/steps.js'],
31+
},
32+
}

test/acceptance/config_test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
Feature('Dynamic Config').config({ url: 'https://google.com' })
22

3-
Scenario('change config 1 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
3+
Scenario('change config 1 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
44
I.amOnPage('/')
55
I.dontSeeInCurrentUrl('github.com')
66
I.seeInCurrentUrl('google.com')
77
})
88

9-
Scenario('change config 2 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
9+
Scenario('change config 2 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
1010
I.amOnPage('/')
1111
I.seeInCurrentUrl('codecept.io')
1212
}).config({ url: 'https://codecept.io' })
1313

14-
Scenario('change config 3 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
14+
Scenario('change config 3 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
1515
I.amOnPage('/')
1616
I.dontSeeInCurrentUrl('codecept.io')
1717
I.seeInCurrentUrl('google.com')
1818
})
1919

20-
Scenario('change config 4 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
20+
Scenario('change config 4 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
2121
I.amOnPage('/')
2222
I.seeInCurrentUrl('codecept.io')
2323
}).config(test => {
2424
return { url: 'https://codecept.io/', capabilities: { 'moz:title': test.title } }
2525
})
2626

27-
Scenario('change config 5 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
27+
Scenario('change config 5 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
2828
I.amOnPage('/')
2929
I.dontSeeInCurrentUrl('codecept.io')
3030
I.seeInCurrentUrl('google.com')
@@ -36,12 +36,12 @@ Scenario('make API call and check response @Playwright', ({ I }) => {
3636
I.seeResponseCodeIsSuccessful()
3737
})
3838

39-
Scenario('change config 6 @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
39+
Scenario('change config 6 @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
4040
I.amOnPage('/')
4141
I.seeInCurrentUrl('codecept.io')
4242
}).config({ url: 'https://codecept.io' })
4343

44-
Scenario('simple page test @WebDriverIO @Puppeteer @Playwright', ({ I }) => {
44+
Scenario('simple page test @WebDriverIO @Puppeteer @Playwright @Obscura', ({ I }) => {
4545
I.amOnPage('https://example.com')
4646
I.see('Example Domain')
4747
})

test/acceptance/gherkin/background.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Puppeteer @WebDriverIO @bdd
1+
@Puppeteer @WebDriverIO @bdd @Obscura
22
Feature: Site test
33
In order to achieve my goals
44
As a persona

test/acceptance/gherkin/basic.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Puppeteer @WebDriverIO @bdd
1+
@Puppeteer @WebDriverIO @bdd @Obscura
22
Feature: Business rules
33
In order to achieve my goals
44
As a persona

test/acceptance/gherkin/before_hook.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Playwright @Puppeteer @WebDriverIO @bdd @hookCapture
1+
@Playwright @Puppeteer @WebDriverIO @bdd @hookCapture @Obscura
22
Feature: Before hooks receive the real scenario
33

44
Background:

test/acceptance/gherkin/examples.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Puppeteer @WebDriverIO @bdd
1+
@Puppeteer @WebDriverIO @bdd @Obscura
22
Feature: Business examples
33
In order to achieve my goals
44
As a persona

test/acceptance/within_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Scenario('within on nested iframe depth 2 and mixed class and xpath selector @We
106106
I.dontSee('Email Address')
107107
})
108108

109-
Scenario('should throw exception if element not found @WebDriverIO @Puppeteer @Playwright', async ({ I }) => {
109+
Scenario('should throw exception if element not found @WebDriverIO @Puppeteer @Playwright @Obscura', async ({ I }) => {
110110
I.amOnPage('/form/textarea')
111111
await within('#grab-multiple', async () => {
112112
return await I.grabTextFrom('#first-link')

0 commit comments

Comments
 (0)