mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-10-05 14:28:08 +03:00
console: improve actions E2E tests with rest connectors
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4520 GitOrigin-RevId: 24d9176dc5f93747e4b3a12ed08171064e75900e
This commit is contained in:
parent
ab8369bdcf
commit
fb1dc2e0ba
@ -6,12 +6,6 @@ export const togglePayloadTransformSection = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const toggleContextArea = () => {
|
||||
cy.getBySel('toggle-context-area').click({
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const toggleRequestTransformSection = () => {
|
||||
cy.getBySel('toggle-request-transform').click({
|
||||
force: true,
|
||||
@ -47,19 +41,6 @@ export const checkTransformRequestUrlError = (
|
||||
}
|
||||
};
|
||||
|
||||
export const typeIntoContextAreaEnvVars = (
|
||||
envVars: { key: string; value: string }[]
|
||||
) => {
|
||||
envVars.forEach((q, i) => {
|
||||
cy.getBySel(`transform-env-vars-kv-key-${i}`).type(q.key, {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
cy.getBySel(`transform-env-vars-kv-value-${i}`).type(q.value, {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const typeIntoRequestQueryParams = (
|
||||
queryParams: { key: string; value: string }[]
|
||||
) => {
|
||||
@ -99,89 +80,3 @@ export const checkTransformRequestBodyError = (exists: boolean) => {
|
||||
cy.getBySel('transform-requestBody-error').should('not.exist');
|
||||
}
|
||||
};
|
||||
|
||||
export const getActionTransfromV1RequestBody = (actionName: string) => ({
|
||||
type: 'bulk',
|
||||
source: 'default',
|
||||
args: [
|
||||
{
|
||||
type: 'set_custom_types',
|
||||
args: {
|
||||
scalars: [],
|
||||
input_objects: [
|
||||
{
|
||||
name: 'SampleInput',
|
||||
description: null,
|
||||
fields: [
|
||||
{
|
||||
name: 'username',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
{
|
||||
name: 'password',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
objects: [
|
||||
{
|
||||
name: 'SampleOutput',
|
||||
description: null,
|
||||
fields: [
|
||||
{
|
||||
name: 'accessToken',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'LoginResponse',
|
||||
fields: [
|
||||
{
|
||||
name: 'accessToken',
|
||||
type: 'String!',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
enums: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'create_action',
|
||||
args: {
|
||||
name: actionName,
|
||||
definition: {
|
||||
arguments: [
|
||||
{
|
||||
name: 'arg1',
|
||||
type: 'SampleInput!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
kind: 'synchronous',
|
||||
output_type: 'SampleOutput',
|
||||
handler: 'http://host.docker.internal:3000',
|
||||
type: 'mutation',
|
||||
headers: [],
|
||||
timeout: null,
|
||||
request_transform: {
|
||||
version: 1,
|
||||
template_engine: 'Kriti',
|
||||
method: 'GET',
|
||||
url: '{{$base_url}}/users',
|
||||
query_params: {},
|
||||
body:
|
||||
'{\n "users": {\n "name": {{$body.input.arg1.username}}\n }\n}',
|
||||
content_type: 'application/json',
|
||||
},
|
||||
},
|
||||
comment: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -68,21 +68,13 @@ if (testMode !== 'cli') {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `test_webhook_transform`
|
||||
|
||||
// --------------------
|
||||
// Pleas note that the custom timeout is not checked explicitly checked, but asserting on
|
||||
// the payload (see the next cy.intercept) means asserting on it too
|
||||
cy.log('**--- Type in the Custom Timeout field**');
|
||||
cy.getBySel('action-timeout-seconds').clear().type('25');
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Click the Create button**');
|
||||
cy.getBySel('create-action-btn').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `create_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
@ -123,8 +115,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Click Save Permissions**');
|
||||
cy.getBySel('save-permissions-for-action').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `create_action_permission`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
@ -163,8 +154,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Check the prompt has been called**');
|
||||
cy.window().its('prompt').should('be.called');
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `drop_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
|
@ -70,15 +70,13 @@ if (testMode !== 'cli') {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `test_webhook_transform`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Click the Create button**');
|
||||
cy.getBySel('create-action-btn').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `create_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
@ -133,8 +131,6 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Click Save Permissions**');
|
||||
cy.getBySel('save-permissions-for-action').click();
|
||||
|
||||
// sure the Console locally works as the one in CI. The request was `create_action_permission`
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
cy.get(
|
||||
@ -168,8 +164,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Click the Delete button**');
|
||||
cy.getBySel('delete-action').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `drop_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
|
@ -1,371 +0,0 @@
|
||||
import { baseUrl, getElementFromClassName } from '../../helpers/dataHelpers';
|
||||
import { setPromptValue } from '../../helpers/common';
|
||||
import { AWAIT_LONG, AWAIT_SHORT } from '../../helpers/constants';
|
||||
import { getTimeoutSeconds } from '../../helpers/eventHelpers';
|
||||
import {
|
||||
toggleRequestTransformSection,
|
||||
togglePayloadTransformSection,
|
||||
typeIntoRequestQueryParams,
|
||||
typeIntoRequestUrl,
|
||||
typeIntoTransformBody,
|
||||
checkTransformRequestUrlError,
|
||||
checkTransformRequestBodyError,
|
||||
checkTransformRequestUrlPreview,
|
||||
clearPayloadTransformBody,
|
||||
clearRequestUrl,
|
||||
toggleContextArea,
|
||||
typeIntoContextAreaEnvVars,
|
||||
getActionTransfromV1RequestBody,
|
||||
} from '../../helpers/webhookTransformHelpers';
|
||||
|
||||
const ACTION_REQUEST_BODY_TRANSFORM_TEXTAREA = 4;
|
||||
|
||||
const statements = {
|
||||
createMutationGQLQuery: `mutation getAccessToken ($username: String!, $password: String!) {
|
||||
login (username: $username, password: $password) {
|
||||
accessToken
|
||||
`,
|
||||
createMutationQueryVars: `{"username": "john", "password": "p"`,
|
||||
createQueryActionText: `type Query {
|
||||
addNumbers (numbers: [Int]): AddResult
|
||||
}`,
|
||||
createQueryActionCustomType: `type AddResult {
|
||||
sum: Int
|
||||
}`,
|
||||
createQueryHandler: 'https://hasura-actions-demo.glitch.me/addNumbers',
|
||||
createQueryGQLQuery: `query {
|
||||
addNumbers(numbers: [1, 2, 3, 4]) {
|
||||
sum
|
||||
`,
|
||||
changeHandlerText: 'http://host.docker.internal:3000',
|
||||
createActionTransform: `type Mutation {
|
||||
login (username: String!, password: String!): LoginResponse
|
||||
}
|
||||
`,
|
||||
createTransformCustomType: `type LoginResponse {
|
||||
accessToken: String!
|
||||
}
|
||||
`,
|
||||
createTransformEnvHandler: '{{MY_WEBHOOK}}',
|
||||
createTransformHandler: 'https://hasura-actions-demo.glitch.me',
|
||||
createTransformIncorrectPayloadBody: `
|
||||
{
|
||||
"userInfo": {
|
||||
"name": {{$input.username}}
|
||||
`,
|
||||
createTransformPayloadBody: `
|
||||
{
|
||||
"userInfo": {
|
||||
"name": {{$body.input.username}},
|
||||
"password": {{$body.input.password}},
|
||||
"type": {{$body.action.name}}
|
||||
`,
|
||||
};
|
||||
|
||||
// NOTE: This test suite does not include cases for relationships, headers and
|
||||
// the codegen part
|
||||
|
||||
const clearActionDef = () => {
|
||||
cy.get('textarea').first().type('{selectall}', { force: true });
|
||||
cy.get('textarea').first().trigger('keydown', {
|
||||
keyCode: 46,
|
||||
which: 46,
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
const clearActionTypes = () => {
|
||||
cy.get('textarea').eq(1).type('{selectall}', { force: true });
|
||||
cy.get('textarea').eq(1).trigger('keydown', {
|
||||
keyCode: 46,
|
||||
which: 46,
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
const clearHandler = () => {
|
||||
cy.getBySel('action-create-handler-input').type('{selectall}{backspace}', {
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
const typeIntoActionDef = (content: string) => {
|
||||
cy.get('textarea').first().type(content, { force: true });
|
||||
};
|
||||
|
||||
const typeIntoActionTypes = (content: string) => {
|
||||
cy.get('textarea').eq(1).type(content, { force: true });
|
||||
};
|
||||
|
||||
const typeIntoHandler = (content: string) => {
|
||||
cy.getBySel('action-create-handler-input').type(content, {
|
||||
force: true,
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
};
|
||||
|
||||
const clickOnCreateAction = () => {
|
||||
cy.getBySel('create-action-btn').scrollIntoView();
|
||||
// hard await before accessing the element
|
||||
cy.wait(AWAIT_SHORT);
|
||||
|
||||
cy.getBySel('create-action-btn').click({ force: true });
|
||||
cy.wait(AWAIT_SHORT);
|
||||
cy.get('.notification', { timeout: AWAIT_LONG })
|
||||
.should('be.visible')
|
||||
.and('contain', 'Created action successfully');
|
||||
};
|
||||
|
||||
export const routeToGraphiql = () => {
|
||||
cy.visit('/api/api-explorer');
|
||||
cy.url({ timeout: AWAIT_LONG }).should('eq', `${baseUrl}/api/api-explorer`);
|
||||
};
|
||||
|
||||
export const verifyMutation = () => {
|
||||
routeToGraphiql();
|
||||
// Type the query
|
||||
cy.on('uncaught:exception', () => {
|
||||
// NOTE: doing this since, there was some exception thrown by the
|
||||
// graphiql editor even though the query was good.
|
||||
// Docs: https://docs.cypress.io/api/events/catalog-of-events.html#To-turn-off-all-uncaught-exception-handling
|
||||
return false;
|
||||
});
|
||||
cy.get('textarea')
|
||||
.eq(0)
|
||||
.type(`{enter}{uparrow}${statements.createMutationGQLQuery}`, {
|
||||
force: true,
|
||||
});
|
||||
cy.get('textarea')
|
||||
.eq(1)
|
||||
.type(`{enter}{uparrow}${statements.createMutationQueryVars}`, {
|
||||
force: true,
|
||||
});
|
||||
cy.get(getElementFromClassName('execute-button')).click();
|
||||
// FIXME: NOT GOOD!
|
||||
cy.get('.cm-property').contains('login');
|
||||
cy.get('.cm-property').contains('accessToken');
|
||||
cy.get('.cm-string').contains('Ew8jkGCNDGAo7p35RV72e0Lk3RGJoJKB');
|
||||
};
|
||||
|
||||
const deleteAction = (promptValue: string) => {
|
||||
setPromptValue(promptValue);
|
||||
cy.getBySel('delete-action').click();
|
||||
cy.window().its('prompt').should('be.called');
|
||||
};
|
||||
|
||||
export const createQueryAction = () => {
|
||||
// Routing to the index page
|
||||
cy.visit('/actions/manage/actions');
|
||||
cy.intercept('*', req => {
|
||||
// send all other requests to the destination server
|
||||
req.reply();
|
||||
});
|
||||
cy.url({ timeout: AWAIT_LONG }).should(
|
||||
'eq',
|
||||
`${baseUrl}/actions/manage/actions`
|
||||
);
|
||||
// Click on create
|
||||
cy.getBySel('data-create-actions').click();
|
||||
// Clear default text on
|
||||
clearActionDef();
|
||||
// type statement
|
||||
typeIntoActionDef(statements.createQueryActionText);
|
||||
// clear defaults on action types
|
||||
clearActionTypes();
|
||||
// type the action type text
|
||||
typeIntoActionTypes(statements.createQueryActionCustomType);
|
||||
// clear handler
|
||||
clearHandler();
|
||||
// type into handler
|
||||
typeIntoHandler(statements.createQueryHandler);
|
||||
// click to create action
|
||||
clickOnCreateAction();
|
||||
};
|
||||
|
||||
export const verifyQuery = () => {
|
||||
cy.on('uncaught:exception', () => {
|
||||
// NOTE: doing this since, there was some exception thrown by the
|
||||
// graphiql editor even though the query was good.
|
||||
// Docs: https://docs.cypress.io/api/events/catalog-of-events.html#To-turn-off-all-uncaught-exception-handling
|
||||
return false;
|
||||
});
|
||||
routeToGraphiql();
|
||||
cy.get('textarea')
|
||||
.eq(0)
|
||||
.type(`{enter}{uparrow}${statements.createQueryGQLQuery}`, { force: true })
|
||||
.wait(4000);
|
||||
cy.get(getElementFromClassName('execute-button')).click();
|
||||
cy.get('.cm-property').contains('addNumbers');
|
||||
cy.get('.cm-property').contains('sum');
|
||||
cy.get('.cm-number').contains('10');
|
||||
};
|
||||
|
||||
export const modifyQueryAction = () => {
|
||||
cy.visit('/actions/manage/addNumbers/modify');
|
||||
cy.url({ timeout: AWAIT_LONG }).should(
|
||||
'eq',
|
||||
`${baseUrl}/actions/manage/addNumbers/modify`
|
||||
);
|
||||
|
||||
clearHandler();
|
||||
typeIntoHandler(statements.changeHandlerText);
|
||||
|
||||
cy.getBySel('save-modify-action-changes').click();
|
||||
|
||||
// permissions part
|
||||
cy.getBySel('actions-permissions').click();
|
||||
|
||||
cy.getBySel('role-textbox').type('MANAGER');
|
||||
|
||||
cy.getBySel('MANAGER-Permission').click();
|
||||
cy.getBySel('save-permissions-for-action').click();
|
||||
|
||||
cy.getBySel('actions-modify').click();
|
||||
};
|
||||
|
||||
export const deleteQueryAction = () => deleteAction('addNumbers');
|
||||
|
||||
export const createActionTransform = () => {
|
||||
// Click on create
|
||||
cy.getBySel('actions-sidebar-add-table').click();
|
||||
// Clear default text on
|
||||
clearActionDef();
|
||||
// type statement
|
||||
typeIntoActionDef(statements.createActionTransform);
|
||||
// clear defaults on action types
|
||||
clearActionTypes();
|
||||
// type the action type text
|
||||
typeIntoActionTypes(statements.createTransformCustomType);
|
||||
cy.getBySel('action-timeout-seconds').clear().type(getTimeoutSeconds());
|
||||
// open request transform section
|
||||
toggleRequestTransformSection();
|
||||
cy.wait(AWAIT_SHORT);
|
||||
cy.getBySel('transform-POST').click();
|
||||
|
||||
// give correct body without webhook handler
|
||||
clearHandler();
|
||||
typeIntoRequestUrl('users');
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// check for error
|
||||
checkTransformRequestUrlError(
|
||||
true,
|
||||
'Please configure your webhook handler to generate request url transform'
|
||||
);
|
||||
|
||||
// give correct body with env var
|
||||
clearHandler();
|
||||
typeIntoHandler(statements.createTransformEnvHandler);
|
||||
// give body without specifying env var
|
||||
clearRequestUrl();
|
||||
typeIntoRequestUrl('/users');
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// check for error
|
||||
checkTransformRequestUrlError(true);
|
||||
|
||||
// add env var in context area
|
||||
toggleContextArea();
|
||||
typeIntoContextAreaEnvVars([
|
||||
{ key: 'MY_WEBHOOK', value: 'https://handler.com' },
|
||||
]);
|
||||
// check there is no error and preview works fine
|
||||
checkTransformRequestUrlError(false);
|
||||
checkTransformRequestUrlPreview('https://handler.com/users');
|
||||
|
||||
// clear handler
|
||||
clearHandler();
|
||||
// type into handler
|
||||
typeIntoHandler(statements.createTransformHandler);
|
||||
|
||||
// give incorrect body
|
||||
clearRequestUrl();
|
||||
typeIntoRequestUrl('{{$url}}/users');
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// check for error
|
||||
checkTransformRequestUrlError(true);
|
||||
|
||||
// give correct body
|
||||
clearRequestUrl();
|
||||
typeIntoRequestUrl('/{{$body.action.name}}');
|
||||
cy.wait(AWAIT_SHORT);
|
||||
typeIntoRequestQueryParams([
|
||||
{ key: 'id', value: '5' },
|
||||
{ key: 'name', value: '{{$body.action.name}}' },
|
||||
]);
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// check there is no error
|
||||
checkTransformRequestUrlError(false);
|
||||
// check the preview is correctly shown
|
||||
checkTransformRequestUrlPreview(
|
||||
'https://hasura-actions-demo.glitch.me/login?name=login&id=5'
|
||||
);
|
||||
|
||||
// open payload transform section
|
||||
togglePayloadTransformSection();
|
||||
|
||||
// give incorrect body
|
||||
clearPayloadTransformBody(ACTION_REQUEST_BODY_TRANSFORM_TEXTAREA);
|
||||
typeIntoTransformBody(
|
||||
statements.createTransformIncorrectPayloadBody,
|
||||
ACTION_REQUEST_BODY_TRANSFORM_TEXTAREA
|
||||
);
|
||||
cy.wait(AWAIT_SHORT);
|
||||
checkTransformRequestBodyError(true);
|
||||
|
||||
// give correct body
|
||||
clearPayloadTransformBody(ACTION_REQUEST_BODY_TRANSFORM_TEXTAREA);
|
||||
typeIntoTransformBody(
|
||||
statements.createTransformPayloadBody,
|
||||
ACTION_REQUEST_BODY_TRANSFORM_TEXTAREA
|
||||
);
|
||||
cy.wait(AWAIT_SHORT);
|
||||
checkTransformRequestBodyError(false);
|
||||
|
||||
// click to create action
|
||||
cy.intercept('*', req => {
|
||||
// send all other requests to the destination server
|
||||
req.reply();
|
||||
});
|
||||
clickOnCreateAction();
|
||||
cy.getBySel('action-timeout-seconds').should('have.value', '25');
|
||||
};
|
||||
|
||||
export const deleteActionTransform = () => deleteAction('login');
|
||||
|
||||
const createV1ActionTransform = (actionName: string) => {
|
||||
cy.request(
|
||||
'POST',
|
||||
'http://localhost:8080/v1/metadata',
|
||||
getActionTransfromV1RequestBody(actionName)
|
||||
).then(response => {
|
||||
expect(response.body).to.not.be.null;
|
||||
expect(response.body).to.be.a('array');
|
||||
expect(response.body[0]).to.have.property('message', 'success'); // true
|
||||
});
|
||||
};
|
||||
|
||||
export const modifyV1ActionTransform = () => {
|
||||
// Creates an action with v1 transform
|
||||
createV1ActionTransform('login');
|
||||
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// modify and save the action, the action should be converted into v2
|
||||
cy.visit('/actions/manage/login/modify');
|
||||
cy.url({ timeout: AWAIT_LONG }).should(
|
||||
'eq',
|
||||
`${baseUrl}/actions/manage/login/modify`
|
||||
);
|
||||
cy.getBySel('transform-POST').click();
|
||||
cy.getBySel('transform-requestUrl')
|
||||
.clear()
|
||||
.type('/{{$body.action.name}}/actions', {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
|
||||
cy.getBySel('save-modify-action-changes').click();
|
||||
cy.get('.notification', { timeout: AWAIT_LONG })
|
||||
.should('be.visible')
|
||||
.and('contain', 'Action saved successfully');
|
||||
|
||||
// delete the action
|
||||
deleteActionTransform();
|
||||
};
|
@ -1,62 +1,59 @@
|
||||
import { modifyV1ActionTransform } from './spec';
|
||||
import { testMode } from '../../helpers/common';
|
||||
import { setMetaData } from '../validators/validators';
|
||||
|
||||
const setup = () => {
|
||||
describe.skip('Setup route', () => {
|
||||
it('Visit the index route', () => {
|
||||
cy.visit('/actions/manage/actions');
|
||||
// Get and set validation metadata
|
||||
setMetaData();
|
||||
});
|
||||
});
|
||||
};
|
||||
// const setup = () => {
|
||||
// describe.skip('Setup route', () => {
|
||||
// it('Visit the index route', () => {
|
||||
// cy.visit('/actions/manage/actions');
|
||||
// // Get and set validation metadata
|
||||
// setMetaData();
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
// TODO: what about the codegen part? Why is it not tested?
|
||||
|
||||
export const runActionsTests = () => {
|
||||
describe.skip('Actions', () => {
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Create Mutation Action', createMutationAction);
|
||||
// export const runActionsTests = () => {
|
||||
// describe.skip('Actions', () => {
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Create Mutation Action', createMutationAction);
|
||||
|
||||
// The test was commented before moving the other ones to mutationAction.e2e.test
|
||||
// it('Verify Mutation Actions on GraphiQL', verifyMutation);
|
||||
// The test was commented before moving the other ones to mutationAction.e2e.test
|
||||
// it('Verify Mutation Actions on GraphiQL', verifyMutation);
|
||||
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Modify Mutation Action', modifyMutationAction);
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Modify Mutation Action', modifyMutationAction);
|
||||
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Delete Mutation Action', deleteMutationAction);
|
||||
// The test has been moved to mutationAction.e2e.test
|
||||
// it('Delete Mutation Action', deleteMutationAction);
|
||||
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Create Query Action', createQueryAction);
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Create Query Action', createQueryAction);
|
||||
|
||||
// The test was commented before moving the other ones to queryAction.e2e.test
|
||||
// it('Verify Query Actions on GraphiQL', verifyQuery);
|
||||
// The test was commented before moving the other ones to queryAction.e2e.test
|
||||
// it('Verify Query Actions on GraphiQL', verifyQuery);
|
||||
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Modify Query Action', modifyQueryAction);
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Modify Query Action', modifyQueryAction);
|
||||
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Delete Query Action', deleteQueryAction);
|
||||
// The test has been moved to queryAction.e2e.test.e2e.test
|
||||
// it('Delete Query Action', deleteQueryAction);
|
||||
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Create Action With Transform', createActionTransform);
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Create Action With Transform', createActionTransform);
|
||||
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Update Action With Transform', modifyActionTransform);
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Update Action With Transform', modifyActionTransform);
|
||||
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Delete Action With Transform', deleteActionTransform);
|
||||
// The test has been moved to actionWithTransform.e2e.test.ts
|
||||
// it('Delete Action With Transform', deleteActionTransform);
|
||||
|
||||
it(
|
||||
'Create an action with V1 Transform and edit it through console, which will lead to the action being saved as V2',
|
||||
modifyV1ActionTransform
|
||||
);
|
||||
});
|
||||
};
|
||||
// The test has been moved to v1ActionWithTransform.e2e.test.ts
|
||||
// it(
|
||||
// 'Create an action with V1 Transform and edit it through console, which will lead to the action being saved as V2',
|
||||
// modifyV1ActionTransform
|
||||
// );
|
||||
// });
|
||||
// };
|
||||
|
||||
if (testMode !== 'cli') {
|
||||
setup();
|
||||
runActionsTests();
|
||||
}
|
||||
// if (testMode !== 'cli') {
|
||||
// setup();
|
||||
// runActionsTests();
|
||||
// }
|
||||
|
@ -56,12 +56,6 @@ if (testMode !== 'cli') {
|
||||
{ force: true, delay: 0 }
|
||||
);
|
||||
|
||||
// --------------------
|
||||
// Pleas note that the custom timeout is not checked explicitly checked, but asserting on
|
||||
// the payload (see the next cy.intercept) means asserting on it too
|
||||
cy.log('**--- Type in the Custom Timeout field**');
|
||||
cy.getBySel('action-timeout-seconds').clearConsoleTextarea().type('25');
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Click the Add Request Options Transform button**');
|
||||
cy.contains('Add Request Options Transform').click();
|
||||
@ -79,8 +73,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Type in the Request URL Template field**');
|
||||
cy.get('[placeholder="URL Template (Optional)..."]').type('users');
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Look for the "Invalid URL" error**');
|
||||
@ -112,8 +105,7 @@ if (testMode !== 'cli') {
|
||||
.clearConsoleTextarea()
|
||||
.type('/users');
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Look for "Missing Env Var" error**');
|
||||
@ -141,8 +133,7 @@ if (testMode !== 'cli') {
|
||||
delay: 1,
|
||||
});
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check the error disappeared**');
|
||||
@ -183,8 +174,7 @@ if (testMode !== 'cli') {
|
||||
.type('{{$url}}/users', { parseSpecialCharSequences: false });
|
||||
});
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Look for "Invalid Path" error**');
|
||||
@ -220,8 +210,7 @@ if (testMode !== 'cli') {
|
||||
}
|
||||
);
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check the error disappeared**');
|
||||
@ -270,8 +259,7 @@ if (testMode !== 'cli') {
|
||||
{ force: true, delay: 1, parseSpecialCharSequences: false }
|
||||
);
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Look for the "Invalid path" error**');
|
||||
@ -304,8 +292,7 @@ if (testMode !== 'cli') {
|
||||
{ force: true, delay: 1, parseSpecialCharSequences: false }
|
||||
);
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI.
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check the error disappeared**');
|
||||
@ -321,8 +308,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Click the Create button**');
|
||||
cy.getBySel('create-action-btn').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `create_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
@ -376,8 +362,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Click on the Save button**');
|
||||
cy.getBySel('save-modify-action-changes').click();
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `create_action_permission`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
@ -427,8 +412,7 @@ if (testMode !== 'cli') {
|
||||
cy.log('**--- Check the prompt has been called**');
|
||||
cy.window().its('prompt').should('be.called');
|
||||
|
||||
// Please note: we should wait for the outgoing request but at the moment of writing, I'm not
|
||||
// sure the Console locally works as the one in CI. The request was `drop_action`
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
|
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Delete the Action straight from the server.
|
||||
*/
|
||||
export function deleteV1LoginAction() {
|
||||
Cypress.log({ message: '**--- Action delete: start**' });
|
||||
|
||||
return cy
|
||||
.request('POST', 'http://localhost:8080/v1/metadata', {
|
||||
type: 'drop_action',
|
||||
args: { name: 'v1Login' },
|
||||
})
|
||||
.then(() => Cypress.log({ message: '**--- Action delete: end**' }));
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
import { readMetadata } from '../services/readMetadata';
|
||||
import { deleteLoginAction } from '../services/deleteLoginAction';
|
||||
|
||||
/**
|
||||
* Ensure the V1 Action exists.
|
||||
*/
|
||||
export function v1LoginActionMustExist() {
|
||||
Cypress.log({ message: '**--- Action check: start**' });
|
||||
|
||||
readMetadata().then(response => {
|
||||
const actionExists = !!response.body.actions?.find(
|
||||
// TODO: properly type it
|
||||
action => action.name === 'TODO:'
|
||||
);
|
||||
|
||||
if (actionExists) {
|
||||
Cypress.log({ message: '**--- The action exists**' });
|
||||
Cypress.log({ message: '**--- Action check: end**' });
|
||||
return;
|
||||
}
|
||||
|
||||
Cypress.log({ message: '**--- The action does not exist**' });
|
||||
|
||||
cy.request('POST', 'http://localhost:8080/v1/metadata', {
|
||||
type: 'bulk',
|
||||
source: 'default',
|
||||
args: [
|
||||
{
|
||||
type: 'set_custom_types',
|
||||
args: {
|
||||
scalars: [],
|
||||
input_objects: [
|
||||
{
|
||||
name: 'SampleInput',
|
||||
description: null,
|
||||
fields: [
|
||||
{
|
||||
name: 'username',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
{
|
||||
name: 'password',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
objects: [
|
||||
{
|
||||
name: 'SampleOutput',
|
||||
description: null,
|
||||
fields: [
|
||||
{
|
||||
name: 'accessToken',
|
||||
type: 'String!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'LoginResponse',
|
||||
fields: [
|
||||
{
|
||||
name: 'accessToken',
|
||||
type: 'String!',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
enums: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'create_action',
|
||||
args: {
|
||||
name: 'v1Login',
|
||||
definition: {
|
||||
arguments: [
|
||||
{
|
||||
name: 'arg1',
|
||||
type: 'SampleInput!',
|
||||
description: null,
|
||||
},
|
||||
],
|
||||
kind: 'synchronous',
|
||||
output_type: 'SampleOutput',
|
||||
handler: 'http://host.docker.internal:3000',
|
||||
type: 'mutation',
|
||||
headers: [],
|
||||
timeout: null,
|
||||
request_transform: {
|
||||
version: 1,
|
||||
template_engine: 'Kriti',
|
||||
method: 'GET',
|
||||
url: '{{$base_url}}/users',
|
||||
query_params: {},
|
||||
body:
|
||||
'{\n "users": {\n "name": {{$body.input.arg1.username}}\n }\n}',
|
||||
content_type: 'application/json',
|
||||
},
|
||||
},
|
||||
comment: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(response => {
|
||||
expect(response.body, 'Response body exists').to.not.be.null;
|
||||
expect(response.body, 'Response body is an array').to.be.a('array');
|
||||
expect(
|
||||
response.body[0],
|
||||
'Response body contains success'
|
||||
).to.have.property('message', 'success');
|
||||
})
|
||||
.then(() => {
|
||||
Cypress.log({ message: '**--- The action has been created**' });
|
||||
Cypress.log({ message: '**--- Action check: end**' });
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { readMetadata } from '../services/readMetadata';
|
||||
import { deleteV1LoginAction } from '../services/deleteV1LoginAction';
|
||||
|
||||
/**
|
||||
* Ensure the Action does not exist.
|
||||
*/
|
||||
export function v1LoginActionMustNotExist() {
|
||||
Cypress.log({ message: '**--- Action check: start**' });
|
||||
|
||||
readMetadata().then(response => {
|
||||
const actionExists = !!response.body.actions?.find(
|
||||
// TODO: properly type it
|
||||
action => action.name === 'v1Login'
|
||||
);
|
||||
|
||||
if (actionExists) {
|
||||
Cypress.log({ message: '**--- The Action must be deleted**' }),
|
||||
deleteV1LoginAction();
|
||||
}
|
||||
});
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
import { testMode } from '../../../helpers/common';
|
||||
|
||||
import { logMetadataRequests } from './utils/requests/logMetadataRequests';
|
||||
import { v1LoginActionMustExist } from './utils/testState/v1LoginActionMustExist';
|
||||
import { v1LoginActionMustNotExist } from './utils/testState/v1LoginActionMustNotExist';
|
||||
|
||||
if (testMode !== 'cli') {
|
||||
describe('V1 Actions with Transform', () => {
|
||||
before(() => {
|
||||
v1LoginActionMustExist();
|
||||
logMetadataRequests();
|
||||
|
||||
cy.visit('/actions/manage/v1Login/modify');
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// Delete the created action, if any
|
||||
v1LoginActionMustNotExist();
|
||||
});
|
||||
|
||||
it('When the users edit a V1 Action with Transform, everything should work', () => {
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**--- Step 3: Mutation Action delete**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
|
||||
cy.get('[data-cy="Change Request Options"]').within(() => {
|
||||
// --------------------
|
||||
cy.log('**--- Choose POST**');
|
||||
cy.contains('POST').click();
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Type in the Request URL Template field**');
|
||||
cy.get('[placeholder="URL Template (Optional)..."]').type(
|
||||
'/{{$body.action.name}}/actions',
|
||||
{
|
||||
delay: 0,
|
||||
parseSpecialCharSequences: false,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Click on the Save button**');
|
||||
cy.getBySel('save-modify-action-changes').click();
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
cy.get(
|
||||
'.notification',
|
||||
// The custom timeout aims to replace the lack of waiting for the outgoing request
|
||||
{ timeout: 10000 }
|
||||
)
|
||||
.should('be.visible')
|
||||
.and('contain', 'Action saved successfully');
|
||||
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**--- Step 2: Action delete**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
cy.log('**------------------------------**');
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Go the the action page**');
|
||||
cy.getBySel('actions-table-links').within(() => {
|
||||
cy.getBySel('v1Login').click();
|
||||
});
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Set the prompt value**');
|
||||
cy.window().then(win => cy.stub(win, 'prompt').returns('v1Login'));
|
||||
|
||||
cy.log('**--- Click the Delete button**');
|
||||
cy.getBySel('delete-action').click();
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check the prompt has been called**');
|
||||
cy.window().its('prompt').should('be.called');
|
||||
|
||||
// Due to the double server/cli mode behavior, we do not assert about the XHR request payload here
|
||||
|
||||
// --------------------
|
||||
cy.log('**--- Check if the success notification is visible**');
|
||||
cy.get(
|
||||
'.notification',
|
||||
// The custom timeout aims to replace the lack of waiting for the outgoing request
|
||||
{ timeout: 10000 }
|
||||
)
|
||||
.should('be.visible')
|
||||
.and('contain', 'Action deleted successfully');
|
||||
|
||||
// TODO: check if it does not exist in the database? Other tests do that
|
||||
});
|
||||
});
|
||||
}
|
@ -32,7 +32,3 @@ import './clearConsoleTextarea';
|
||||
Cypress.Commands.add('getBySel', (selector, ...args) => {
|
||||
return cy.get(`[data-test=${selector}]`, ...args);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getBySelLike', (selector, ...args) => {
|
||||
return cy.get(`[data-test*=${selector}]`, ...args);
|
||||
});
|
||||
|
10
console/cypress/support/index.d.ts
vendored
10
console/cypress/support/index.d.ts
vendored
@ -7,19 +7,13 @@ declare namespace Cypress {
|
||||
* <button data-test="greeting"> </button>
|
||||
* @example cy.getBySel('greeting')
|
||||
*/
|
||||
getBySel(value: string): Chainable<Element>;
|
||||
/**
|
||||
* Custom command to select DOM element by data-test* attribute.
|
||||
* <button data-test="save_me_oh_God"> </button>
|
||||
* @example cy.getBySelLike('save_me')
|
||||
*/
|
||||
getBySelLike(value: string): Chainable<Element>;
|
||||
getBySel(value: string): Chainable<JQuery<Element>>;
|
||||
/**
|
||||
* Custom command to work around the fact that cy.clear sometimes fails at clearing the
|
||||
* Console's textarea
|
||||
* @example cy.get('textarea').clearConsoleTextarea()
|
||||
*/
|
||||
clearConsoleTextarea(): Chainable<Element>;
|
||||
clearConsoleTextarea(): Chainable<JQuery<HTMLTextAreaElement>>;
|
||||
/**
|
||||
* Visit the initial empty page.
|
||||
* Console's textarea
|
||||
|
Loading…
Reference in New Issue
Block a user