Skip to content

Commit 6849237

Browse files
beaussanhasura-bot
authored andcommitted
frontend: make a archive copy of the console files just in case
GitOrigin-RevId: a4074a537809b256caff6a16ef4b1d3853fcb16c
1 parent bdcbda5 commit 6849237

File tree

2,338 files changed

+335375
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,338 files changed

+335375
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
"__version": "10.4.0"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getElementFromAlias } from '../../helpers/dataHelpers';
2+
3+
export const viewOnboarding = () => {
4+
// Click on create
5+
cy.get(getElementFromAlias('onboarding-popup'))
6+
.should('be.visible')
7+
.should('contain.text', `Hi there, let's get started with Hasura!`);
8+
// cy.get(getElementFromAlias('btn-hide-for-now')).click();
9+
};
10+
export const hideNow = () => {
11+
// Click on create
12+
cy.get(getElementFromAlias('btn-hide-for-now')).click();
13+
cy.get(getElementFromAlias('onboarding-popup')).should('not.exist');
14+
};
15+
16+
export const dontShowAgain = () => {
17+
// Click on create
18+
cy.reload();
19+
cy.get(getElementFromAlias('onboarding-popup')).should('be.visible');
20+
21+
cy.get(getElementFromAlias('btn-ob-dont-show-again')).click();
22+
cy.get(getElementFromAlias('onboarding-popup')).should('not.exist');
23+
cy.reload();
24+
cy.get(getElementFromAlias('onboarding-popup')).should('not.exist');
25+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { viewOnboarding, hideNow, dontShowAgain } from './spec';
2+
import { testMode } from '../../helpers/common';
3+
import { setMetaData } from '../validators/validators';
4+
import { getIndexRoute } from '../../helpers/dataHelpers';
5+
6+
const setup = () => {
7+
// Temporarily skipped because of its flakiness, see: https://github.com/hasura/graphql-engine-mono/issues/5433
8+
// TODO: Fix and restore it
9+
describe.skip('Setup route', () => {
10+
it('Visit the index route', () => {
11+
cy.visit(getIndexRoute());
12+
setMetaData();
13+
});
14+
});
15+
};
16+
17+
export const runActionsTests = () => {
18+
describe('onboarding', () => {
19+
// Temporarily skipped because of its flakiness, see: https://github.com/hasura/graphql-engine-mono/issues/5433
20+
// TODO: Fix and restore it
21+
it.skip('should show onboarding guide', viewOnboarding);
22+
23+
// Temporarily skipped because of its flakiness, see: https://github.com/hasura/graphql-engine-mono/issues/5433
24+
// TODO: Fix and restore it
25+
it.skip('should hide when user click on Hide Now', hideNow);
26+
27+
// Temporarily skipped because of its flakiness, see: https://github.com/hasura/graphql-engine-mono/issues/5433
28+
// TODO: Fix and restore it
29+
it.skip(
30+
'should hide forever when user click on Dont Show again',
31+
dontShowAgain
32+
);
33+
});
34+
};
35+
36+
if (testMode !== 'cli') {
37+
setup();
38+
runActionsTests();
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { testMode } from '../../../helpers/common';
2+
3+
import { logMetadataRequests } from './utils/requests/logMetadataRequests';
4+
import { addNumbersActionMustNotExist } from './utils/testState/addNumbersActionMustNotExist';
5+
6+
// NOTE: This test suite does not include cases for relationships, headers and the codegen part
7+
8+
if (testMode !== 'cli') {
9+
// Temporarily skipped because of its flakiness, see: https://github.com/hasura/graphql-engine-mono/issues/5433
10+
// TODO: Fix and restore it
11+
describe.skip('Query Actions', () => {
12+
before(() => {
13+
addNumbersActionMustNotExist();
14+
logMetadataRequests();
15+
16+
cy.visit('/actions/manage/actions');
17+
});
18+
19+
after(() => {
20+
// Cleanup after the whole test file run
21+
22+
// Ensure the application is not there when manually deleting the created action to avoid any
23+
// potential client-side error that makes the test fail
24+
cy.visitEmptyPage();
25+
26+
// Delete the created action, if any
27+
addNumbersActionMustNotExist();
28+
});
29+
30+
it('When the users create, edit, and delete a Query Action, everything should work', () => {
31+
cy.log('**------------------------------**');
32+
cy.log('**------------------------------**');
33+
cy.log('**------------------------------**');
34+
cy.log('**--- Step 1: Query Action creation**');
35+
cy.log('**------------------------------**');
36+
cy.log('**------------------------------**');
37+
cy.log('**------------------------------**');
38+
39+
// --------------------
40+
cy.log('**--- Click on the Create button of the Actions panel**');
41+
cy.getBySel('data-create-actions').click();
42+
43+
// --------------------
44+
// Assign an alias to the most unclear selectors for future references
45+
cy.get('textarea').eq(0).as('actionDefinitionTextarea');
46+
cy.get('textarea').eq(1).as('typeConfigurationTextarea');
47+
48+
// --------------------
49+
cy.log('**--- Type in the Action Definition textarea**');
50+
cy.get('@actionDefinitionTextarea')
51+
.clearConsoleTextarea()
52+
.type(
53+
`type Query {
54+
addNumbers (numbers: [Int]): AddResult
55+
}`,
56+
{ force: true, delay: 0 }
57+
);
58+
59+
// --------------------
60+
cy.log('**--- Type in the Type Configuration textarea**');
61+
cy.get('@typeConfigurationTextarea')
62+
.clearConsoleTextarea()
63+
.type(
64+
`type AddResult {
65+
sum: Int
66+
}`,
67+
{ force: true, delay: 0 }
68+
);
69+
70+
// --------------------
71+
cy.log('**--- Type in the Webhook Handler field**');
72+
cy.getBySel('action-create-handler-input')
73+
.clearConsoleTextarea()
74+
.type('https://hasura-actions-demo.glitch.me/addNumbers', {
75+
delay: 0,
76+
parseSpecialCharSequences: false,
77+
});
78+
79+
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
80+
81+
// --------------------
82+
cy.log('**--- Click the Create button**');
83+
cy.getBySel('create-action-btn').click();
84+
85+
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
86+
87+
// --------------------
88+
cy.log('**--- Check if the success notification is visible**');
89+
cy.expectSuccessNotificationWithTitle('Created action successfully');
90+
91+
cy.log('**------------------------------**');
92+
cy.log('**------------------------------**');
93+
cy.log('**------------------------------**');
94+
cy.log('**--- Step 2: Permission add and Handler change**');
95+
cy.log('**------------------------------**');
96+
cy.log('**------------------------------**');
97+
cy.log('**------------------------------**');
98+
99+
// --------------------
100+
101+
cy.log('**--- Go the the action page**');
102+
cy.getBySel('actions-table-links').within(() => {
103+
cy.getBySel('addNumbers').click();
104+
});
105+
106+
// --------------------
107+
cy.log('**--- Type in the Webhook Handler field**');
108+
cy.getBySel('action-create-handler-input')
109+
.clearConsoleTextarea()
110+
.type('http://host.docker.internal:3000', {
111+
delay: 0,
112+
// parseSpecialCharSequences: false,
113+
});
114+
115+
// --------------------
116+
cy.log('**--- Click on the Save button**');
117+
cy.getBySel('save-modify-action-changes').click();
118+
119+
// --------------------
120+
cy.log('**--- Click the Permissions tab**');
121+
cy.getBySel('actions-permissions').click();
122+
123+
// --------------------
124+
cy.log('**--- Enter a new role**');
125+
cy.getBySel('role-textbox').type('manager');
126+
cy.getBySel('manager-Permission').click();
127+
128+
// --------------------
129+
cy.log('**--- Click Save Permissions**');
130+
cy.getBySel('save-permissions-for-action').click();
131+
132+
// --------------------
133+
cy.log('**--- Check if the success notification is visible**');
134+
cy.expectSuccessNotificationWithTitle('Permission saved successfully');
135+
136+
cy.log('**------------------------------**');
137+
cy.log('**------------------------------**');
138+
cy.log('**------------------------------**');
139+
cy.log('**--- Step 3: Query Action delete**');
140+
cy.log('**------------------------------**');
141+
cy.log('**------------------------------**');
142+
cy.log('**------------------------------**');
143+
144+
// --------------------
145+
cy.log('**--- Go the the action page**');
146+
cy.getBySel('actions-table-links').within(() => {
147+
cy.getBySel('addNumbers').click();
148+
});
149+
150+
// --------------------
151+
cy.log('**--- Set the prompt value**');
152+
cy.window().then(win => cy.stub(win, 'prompt').returns('addNumbers'));
153+
154+
cy.log('**--- Click the Delete button**');
155+
cy.getBySel('delete-action').click();
156+
157+
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
158+
159+
// --------------------
160+
cy.log('**--- Check if the success notification is visible**');
161+
cy.expectSuccessNotificationWithTitle('Action deleted successfully');
162+
});
163+
});
164+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
"__version": "10.4.0"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
interface SingleMetadataRequest {
2+
type: string;
3+
// There are a lot of other fields, but tracking them is not important for the purpose of this module
4+
}
5+
6+
interface BulkMetadataRequest {
7+
type: 'bulk';
8+
args: SingleMetadataRequest[];
9+
}
10+
11+
type MetadataRequest = SingleMetadataRequest | BulkMetadataRequest;
12+
13+
/*
14+
* Log all the requests outgoing to the Metadata endpoint.
15+
* This is useful to have a glance of the requests that are going to the server.
16+
*/
17+
export function logMetadataRequests() {
18+
cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => {
19+
const noArgs = !req.body.args;
20+
21+
if (noArgs) return;
22+
23+
const requestBody = req.body as MetadataRequest;
24+
25+
if (requestBody.type === 'bulk' || requestBody.type === 'concurrent_bulk') {
26+
const request = requestBody as BulkMetadataRequest;
27+
Cypress.log({ message: '*--- Bulk request*' });
28+
29+
request.args.forEach(arg =>
30+
Cypress.log({ message: `*--- Request: ${arg.type}*` })
31+
);
32+
} else {
33+
Cypress.log({ message: `*--- Request: ${requestBody.type}*` });
34+
}
35+
});
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Wait for a bunch of requests to be settled before proceeding with the test.
3+
*
4+
* Alternatively, https://github.com/bahmutov/cypress-network-idle could be used
5+
*
6+
* This is a workaround for "element is 'detached' from the DOM" Cypress' error (see the issue
7+
* linked below). Since the UI gets re-rendered because of the requests, this utility ensures that
8+
* all the requests parallelly made by the UI are settled before proceeding with the test. Hance, it
9+
* ensure the UI won't re-render during the next interaction.
10+
*
11+
* What are the requests that must be awaited? By looking at the Cypress Test Runner, they are the
12+
* following, made parallelly or in a rapid series.
13+
* 1. export_metadata
14+
* 2. export_metadata
15+
* 3. export_metadata
16+
* 4. test_webhook_transform
17+
* 5. test_webhook_transform
18+
* 6. test_webhook_transform
19+
* 7. test_webhook_transform
20+
* At the moment of writing, I'm not sure the number of requests are fixed or not. If they are fixed,
21+
* using the cy.intercept `times` options would result in a more expressive and less convoluted code.
22+
*
23+
* To give you an overall idea, this is a timeline of the requests
24+
*
25+
* all requests start all requests end
26+
* | | | |
27+
* |--🚦🔴--1--2--3--4--5--6--7----------------------------1--2--3--4--5--6-7--🚦🟢--|
28+
*
29+
*
30+
* ATTENTION: Despite the defensive approach and the flakiness-removal purpose, this function could
31+
* introduced even more flakiness because of its empiric approach. In case of failures, it must be
32+
* carefully evaluated when/if keeping it or thinking about a better approach.
33+
* In generale, this solution does not scale, at should not be spread among the tests.
34+
*
35+
* @see https://github.com/cypress-io/cypress/issues/7306
36+
* @see https://glebbahmutov.com/blog/detached/
37+
* @see https://github.com/bahmutov/cypress-network-idle
38+
*/
39+
40+
import 'cypress-wait-until';
41+
42+
export function waitForPostCreationRequests() {
43+
let waitCompleted = false;
44+
45+
cy.log('*--- All requests must be settled*');
46+
47+
const pendingRequests = new Map();
48+
cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => {
49+
if (waitCompleted) return;
50+
51+
Cypress.log({ message: '*--- Request pending*' });
52+
53+
pendingRequests.set(req, true);
54+
55+
req.continue(() => {
56+
Cypress.log({ message: '*--- Request settled*' });
57+
58+
pendingRequests.delete(req);
59+
});
60+
});
61+
62+
Cypress.log({ message: '*--- Waiting for the first request to start*' });
63+
64+
// Check if at least one request has been caught. This check must protect from the following case
65+
//
66+
// check requests start test failure, the requests got the UI re-rendered
67+
// | | |
68+
// |--🚦🔴----⚠️---🚦🟢-------1-2-3-4-5-6-7-1----------💥
69+
//
70+
// where checking that "there are no pending requests" falls in the false positive case where
71+
// there are no pending requests because no one started at all.
72+
//
73+
// The check runs every millisecond to be 100% sure that no request can escape (ex. because of a
74+
// super fast server). A false-negative case represented here
75+
//
76+
// requests start requests end check check test failure, no first request caught
77+
// | | | | | | |
78+
// |--🚦🔴--1-2-3-4-5-6-7-1-2-3-4-5-6-7--⚠️------------------⚠️------------------💥
79+
cy.waitUntil(() => pendingRequests.size > 0, {
80+
timeout: 5000, // 5 seconds is the default Cypress wait for a request to start
81+
interval: 1,
82+
errorMsg: 'No first request caught',
83+
});
84+
85+
Cypress.log({ message: '*--- Waiting for all the requests to start*' });
86+
87+
// Let pass some time to collect all the requests. Otherwise, it could detect that the first
88+
// request complete and go on with the test, even if another one will be performed in a while.
89+
//
90+
// This fixed wait protects from the following timeline
91+
//
92+
// 1st request start first request end other requests start test failure, the requests got the UI re-rendered
93+
// | | | |
94+
// |--🚦🔴---1---------------------1----🚦🟢----------------2-3-4-5-6-7-1----------💥
95+
//
96+
// Obviously, it is an empiric waiting, that also slows down the test.
97+
cy.wait(500);
98+
99+
Cypress.log({ message: '*--- Waiting for all the requests to be settled*' });
100+
101+
cy.waitUntil(() => pendingRequests.size === 0, {
102+
timeout: 30000, // 30 seconds is the default Cypress wait for the request to complete
103+
errorMsg: 'Some requests are not settled yet',
104+
}).then(() => {
105+
waitCompleted = true;
106+
});
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Delete the Action straight from the server.
3+
*/
4+
export function deleteAddNumbersAction() {
5+
Cypress.log({ message: '**--- Action delete: start**' });
6+
7+
return cy
8+
.request('POST', 'http://localhost:8080/v1/metadata', {
9+
type: 'drop_action',
10+
args: { name: 'addNumbers' },
11+
})
12+
.then(() => Cypress.log({ message: '**--- Action delete: end**' }));
13+
}

0 commit comments

Comments
 (0)