Skip to content

Commit b947d17

Browse files
committed
Reduce number of calls to form templates API (cypress)
1 parent e25f9b1 commit b947d17

5 files changed

Lines changed: 123 additions & 1 deletion

File tree

.github/workflows/cypress.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,37 @@ jobs:
6666
if: steps.cache-npm.outputs.cache-hit != 'true'
6767
run: npm ci --legacy-peer-deps --include=dev
6868

69+
# Serve the form-templates API from a fixture instead of calling
70+
# formidableforms.com on every run. The cache key is the UTC date, so
71+
# the fixture is refreshed at most once a day and all four shards share
72+
# the one copy - without this, each shard fetches it separately. If the
73+
# fetch fails the committed fixture is used, so the suite still runs
74+
# when the API is unreachable.
75+
- name: Get current date
76+
id: date
77+
run: echo "date=$( date -u +%Y-%m-%d )" >> "$GITHUB_OUTPUT"
78+
79+
- name: Cache form templates API response
80+
id: cache-templates
81+
uses: actions/cache@v4
82+
with:
83+
path: tests/mu-plugins/form-templates-api.json
84+
key: form-templates-${{ steps.date.outputs.date }}
85+
86+
- name: Refresh form templates fixture
87+
if: steps.cache-templates.outputs.cache-hit != 'true'
88+
run: |
89+
# Write to a temp file first so a partial or failed response never
90+
# clobbers the committed fallback.
91+
if curl -fsS --max-time 40 -A 'formidable-e2e' \
92+
'https://formidableforms.com/wp-json/form-templates/v1/list?l=RlJFRVRFTVBMQVRFUyEhIQ%3D%3D' \
93+
-o /tmp/form-templates-api.json && [ -s /tmp/form-templates-api.json ]; then
94+
mv /tmp/form-templates-api.json tests/mu-plugins/form-templates-api.json
95+
echo "Refreshed the form templates fixture from the API."
96+
else
97+
echo "Could not reach the templates API; using the committed fixture."
98+
fi
99+
69100
- name: Set up WP environment
70101
run: npm run env start
71102

.wp-env.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
"plugins": [
55
"."
66
],
7+
"mappings": {
8+
"wp-content/mu-plugins": "./tests/mu-plugins"
9+
},
710
"env": {
811
"tests": {
912
"mappings": {
13+
"wp-content/mu-plugins": "./tests/mu-plugins",
1014
"wp-cli.yml": "./tests/bin/wp-cli.yml"
1115
}
1216
}
1317
}
14-
}
18+
}

tests/mu-plugins/form-templates-api.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
// Forces the welcome-tour checklist off in the e2e test environment.
3+
//
4+
// On a fresh install the checklist renders expanded on its 'create-form'
5+
// step and its header overlays the form builder, covering
6+
// #frm-save-form-name-button so `cy.click()` fails actionability.
7+
//
8+
// The suite used to get away with this by accident: Cypress runs root-level
9+
// specs first, so admin-a11y.cy.js was always spec 1 of 18 and clicked the
10+
// checklist away, and because FrmWelcomeTourController stores its state in
11+
// the site-wide `frm-welcome-tour` option, every later spec inherited a
12+
// dismissed tour. Sharding removes that guarantee - whichever spec runs
13+
// first on a given shard now meets a virgin site - so the state has to be
14+
// set deterministically instead of inherited from a neighbour.
15+
//
16+
// Filtering rather than seeding the option means save_checklist() can't
17+
// write over it mid-run. `active_step_key` is required alongside
18+
// `dismissed`: get_usage_data() reads it whenever `dismissed` is truthy and
19+
// would otherwise emit an undefined-index warning into debug.log.
20+
add_filter(
21+
'pre_option_frm-welcome-tour',
22+
function () {
23+
return array(
24+
'completed_steps' => array(),
25+
'active_step_key' => 'create-form',
26+
'dismissed' => true,
27+
);
28+
}
29+
);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
// Serves the form-templates API from a local fixture in the e2e test
3+
// environment, so the suite never depends on a live call to
4+
// formidableforms.com.
5+
//
6+
// Two things go wrong without this. A fresh wp-env has an empty template
7+
// cache, and FrmFormApi::get_api_info() returns an empty array outright when
8+
// another request for the same data is already in flight (the is_running()
9+
// guard) rather than waiting for it - so the templates list renders empty and
10+
// assertions like [frm-search-text="user registration"] never match. The
11+
// `Get Instant Access` signup flow then calls reset_cached(), clearing the
12+
// cache mid-run and re-opening the same window for whatever runs next.
13+
//
14+
// Sharding sharpened this: every shard is its own wp-env with its own cold
15+
// cache, so one live fetch per run became one per shard.
16+
//
17+
// Filtering pre_http_request rather than seeding the cache option keeps this
18+
// independent of FrmFormApi's cache internals - the option key is derived
19+
// from the license, and reset_cached() deletes it - and it is the standard
20+
// WordPress way to stub an outbound request.
21+
//
22+
// The fixture sits beside this file on purpose. The whole mu-plugins
23+
// directory is mapped to a known path inside the container, whereas the
24+
// plugin directory is named `formidable` locally and `formidable-forms` in
25+
// CI, so a path built from the plugin folder would break in one of the two.
26+
// WordPress only auto-loads .php from the mu-plugins root, so the .json
27+
// sibling is inert.
28+
add_filter(
29+
'pre_http_request',
30+
function ( $preempt, $args, $url ) {
31+
if ( false === strpos( $url, '/wp-json/form-templates/v1/list' ) ) {
32+
return $preempt;
33+
}
34+
35+
$fixture = __DIR__ . '/form-templates-api.json';
36+
37+
if ( ! is_readable( $fixture ) ) {
38+
// Let the real request through rather than failing the run with an
39+
// empty template list, which is the confusing symptom this exists
40+
// to prevent.
41+
return $preempt;
42+
}
43+
44+
return array(
45+
'headers' => array(),
46+
'body' => file_get_contents( $fixture ),
47+
'response' => array(
48+
'code' => 200,
49+
'message' => 'OK',
50+
),
51+
'cookies' => array(),
52+
'filename' => null,
53+
);
54+
},
55+
10,
56+
3
57+
);

0 commit comments

Comments
 (0)