Skip to content

Commit 8e71ce6

Browse files
authored
Merge pull request #9623 from asirvadAbrahamVarghese/enhance-intercept-api-command
Enhance intercept api command
2 parents 5008352 + 27f2bc8 commit 8e71ce6

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

cypress/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ ManageIQ implements the following cypress extensions:
6363

6464
##### api_commands
6565

66-
* `cy.interceptApi({ alias, method = 'POST', urlPattern, triggerFn, onApiResponse })` - intercepts API calls and waits for them to complete. This command will: 1) Register an intercept(in method-alias format e.g. post-myApiAlias) for the given alias & URL pattern if not already registered, 2) Execute the trigger function that makes the API call, 3) Wait for the intercepted request to complete. `alias` is the string for a unique alias for this interception. `method` is the string for the HTTP method (default: 'POST'). `urlPattern` is the string or RegExp for the URL pattern to intercept. `triggerFn` is the function that triggers the API call. `onApiResponse` is an optional callback function that receives the interception object after the API call completes. Use this to perform assertions on the response, extract data, or perform additional actions based on the API result. Default is a no-op function. e.g. `cy.interceptApi({ alias: 'getUsers', method: 'GET', urlPattern: '/api/users', triggerFn: () => cy.get('#load-users').click(), onApiResponse: (interception) => { expect(interception.response.statusCode).to.equal(200); } });`
66+
* `cy.interceptApi({ alias, method = 'POST', urlPattern, waitOnlyIfRequestIntercepted, responseInterceptor, triggerFn, onApiResponse })` - intercepts API calls and waits for them to complete. This command will: 1) Register an intercept(in method-alias format e.g. post-myApiAlias) for the given alias & URL pattern if not already registered, 2) Execute the trigger function that makes the API call, 3) Wait for the intercepted request to complete. `alias` is the string for a unique alias for this interception. `method` is the string for the HTTP method (default: 'POST'). `urlPattern` is the string or RegExp for the URL pattern to intercept. `waitOnlyIfRequestIntercepted` is a boolean that when set to true, the command will only wait for the response if the request was actually intercepted (useful for conditional API calls - default: false). `responseInterceptor` is an optional function that can modify the response before it's returned to the application, with options to stub responses (`req.reply()`), let requests go to origin (`req.continue()`), or modify origin responses (`req.continue((res) => res.send())`). e.g. `{ responseInterceptor: (req) => req.reply({ body: { customData: 'value' } }) }`, `{ responseInterceptor: (req) => req.reply({ fixture: 'users.json' }) }`, `{ responseInterceptor: (req) => req.continue((res) => { res.send(200, { modified: true }) }) }`, `triggerFn` is the function that triggers the API call. e.g. `{ triggerFn: () => { cy.get('button').click(); } }`. `onApiResponse` is an optional callback function that receives the interception object after the API call completes. Use this to perform assertions on the response, extract data, or perform additional actions based on the API result. Default is a no-op function. e.g. `{ onApiResponse: (interception) => { expect(interception.response.statusCode).to.equal(200); } }`. Usage example: `cy.interceptApi({ alias: 'getUsers', method: 'GET', urlPattern: '/api/users', triggerFn: () => cy.get('#load-users').click(), responseInterceptor: (req) => req.reply({ body: { name: "stubbed value" } }), onApiResponse: (interception) => { expect(interception.response.statusCode).to.equal(200); } });`
6767
* `cy.getInterceptedApiAliases()` - returns the intercepted API aliases stored in Cypress environment variables.
6868
* `cy.setInterceptedApiAlias(aliasKey, aliasValue)` - sets an intercepted API alias in the Cypress environment variables. `aliasKey` is the string for the key/name of the alias to set. `aliasValue` is an optional string for the value to store for the alias (defaults to the same as the key). e.g. `cy.setInterceptedApiAlias('getUsersApi');`, `cy.setInterceptedApiAlias('getUsersApi', 'customValue');`
6969
* `cy.resetInterceptedApiAliases()` - resets the intercepted API aliases stored in Cypress environment variables.

cypress/support/commands/api_commands.js

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ const setRequestIntercepted = (value) =>
7171
/**
7272
* Gets the current value of the request interception flag from Cypress environment.
7373
* This flag indicates whether a request matching an intercept pattern was detected.
74-
* @returns {boolean} The current value of the request interception flag
74+
* @returns {boolean} The current value of the request interception flag, by default returns false
7575
*/
76-
const getRequestIntercepted = () => Cypress.env('wasRequestIntercepted');
76+
const getRequestIntercepted = () =>
77+
Cypress.env('wasRequestIntercepted') || false;
7778

7879
/**
7980
* Custom command to intercept API calls and wait for them to complete.
@@ -84,9 +85,22 @@ const getRequestIntercepted = () => Cypress.env('wasRequestIntercepted');
8485
*
8586
* @param {Object} options - The options for the intercept
8687
* @param {string} options.alias - Unique alias for this interception
87-
* @param {string} options.method - HTTP method (default: 'POST')
88+
* @param {string} [options.method] - HTTP method (default: 'POST')
8889
* @param {string|RegExp} options.urlPattern - URL pattern to intercept
89-
* @param {Function} options.triggerFn - Function that triggers the API call
90+
* @param {boolean} [options.waitOnlyIfRequestIntercepted] - When set to true(default: false), the command will only wait for the response
91+
* if the request was actually intercepted. This is useful for conditional API calls that may or may not happen like in tree navigations.
92+
* If false (default), the command will always wait for the intercepted request, where a request is always expected (e.g., button events).
93+
* @param {Function} options.triggerFn - Function that triggers the API call. e.g. { triggerFn: () => { cy.get('button').click(); } }
94+
* @param {Function} [options.responseInterceptor] - Optional function that can modify the response before it's returned to the application.
95+
* This function receives the request object and can handle the response in different ways:
96+
* 1. req.reply({body: {...}}) - Immediately respond with a stubbed response (request never goes to origin)
97+
* 2. req.continue() - Let the request go to the origin server without modification
98+
* 3. req.continue((res) => { res.send({...}) }) - Let the request go to origin, then modify the response
99+
* Examples:
100+
* - Stub response: { responseInterceptor: (req) => req.reply({ body: { customData: 'value' } }) }
101+
* - Using fixture to stub response: { responseInterceptor: (req) => req.reply({ fixture: 'users.json' }) }
102+
* - Pass through to origin: { responseInterceptor: (req) => req.continue() }
103+
* - Modify origin response: { responseInterceptor: (req) => req.continue((res) => { res.send(200, { modified: true }) }) }
90104
* @param {Function} [options.onApiResponse] - Optional callback function that receives the interception object after the API call completes.
91105
* Use this to perform assertions on the response, extract data, or perform additional actions based on the API result.
92106
* Default is a no-op function. e.g. { onApiResponse: (interception) => { expect(interception.response.statusCode).to.equal(200); } }
@@ -97,10 +111,14 @@ Cypress.Commands.add(
97111
alias,
98112
method = 'POST',
99113
urlPattern,
114+
waitOnlyIfRequestIntercepted = false,
100115
triggerFn,
101116
onApiResponse = () => {
102117
/* default implementation */
103118
},
119+
responseInterceptor = () => {
120+
/* default implementation */
121+
},
104122
}) => {
105123
/* ===== TODO: Remove this block once interceptApi command becomes stable ===== */
106124
const envVars = Cypress.env();
@@ -114,12 +132,17 @@ Cypress.Commands.add(
114132
// Check if this request is already registered
115133
const isAlreadyRegistered = !!interceptedAliasesMap[aliasObjectKey];
116134
// Setting wasRequestIntercepted flag to false initially
117-
setRequestIntercepted(false);
135+
if (waitOnlyIfRequestIntercepted) {
136+
setRequestIntercepted(false);
137+
}
118138
// Register the intercept if not already done
119139
if (!isAlreadyRegistered) {
120-
cy.intercept(method, urlPattern, () => {
140+
cy.intercept(method, urlPattern, (req) => {
121141
// Setting wasRequestIntercepted flag to true after request is intercepted
122-
setRequestIntercepted(true);
142+
if (waitOnlyIfRequestIntercepted) {
143+
setRequestIntercepted(true);
144+
}
145+
responseInterceptor(req);
123146
}).as(alias);
124147
cy.setInterceptedApiAlias(aliasObjectKey, alias);
125148
}
@@ -129,8 +152,16 @@ Cypress.Commands.add(
129152

130153
// Wait for the intercepted request to complete
131154
cy.then(() => {
132-
const isRequestIntercepted = getRequestIntercepted();
133-
if (isRequestIntercepted) {
155+
// If waitOnlyIfRequestIntercepted is true, check if the request was intercepted
156+
// and then wait for the response
157+
if (waitOnlyIfRequestIntercepted) {
158+
const isRequestIntercepted = getRequestIntercepted();
159+
if (isRequestIntercepted) {
160+
cy.wait(`@${alias}`).then(onApiResponse);
161+
}
162+
}
163+
// If waitOnlyIfRequestIntercepted is not required then directly wait for the response
164+
else {
134165
cy.wait(`@${alias}`).then(onApiResponse);
135166
}
136167
});

cypress/support/commands/explorer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Cypress.Commands.add('accordion', (title) => {
1414
alias: 'accordionSelectApi',
1515
urlPattern: /\/[^\/]+\/accordion_select\?id=.*/,
1616
triggerFn: () => cy.wrap(el).click(),
17+
waitOnlyIfRequestIntercepted: true,
1718
});
1819
}
1920
});
@@ -83,6 +84,7 @@ Cypress.Commands.add('selectAccordionItem', (accordionPath) => {
8384
alias: 'treeSelectApi',
8485
urlPattern: /\/[^\/]+\/tree_select\?id=.*&text=.*/,
8586
triggerFn: () => cy.wrap(currentLiElement).click(),
87+
waitOnlyIfRequestIntercepted: true,
8688
});
8789
return;
8890
}

0 commit comments

Comments
 (0)