From 6bf0a49cd6510ab6b069909affe4909a9b1636d2 Mon Sep 17 00:00:00 2001 From: Varun Choudhary <68095256+Varun-Choudhary@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:11:16 +0530 Subject: [PATCH] console: e2e snapshot testing for remote schema This PR adds e2e snapshot testing for remote schema. We are testing it in 2 ways - 1. testing the shortest possible path to create RS and then modifying it to the longest possible path 2. testing the longest possible path to create RS and then modifying it to shortest possible path 3. [ see doc](https://docs.google.com/document/d/1NjZsvd6xOq90lNMai8nKBaWl-LqBWrkiZCHSQ7wusdE/edit) for more detail PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8383 GitOrigin-RevId: d045219ca7db00e797492e9d61efb25283c1b3b3 --- .../__snapshots__/create-rs.test.ts.snap | 74 ++++ .../create-remote-schema/create-rs.test.ts | 337 ++++++++++++++++++ .../Services/RemoteSchema/Common/Common.js | 2 + .../GraphQLCustomization/FieldNames.tsx | 5 +- .../GraphQLCustomizationEdit.tsx | 3 + .../GraphQLCustomization/TypeMapping.tsx | 3 + .../components/Create/Create.stories.tsx | 26 +- .../components/KeyValueHeader.tsx | 3 + 8 files changed, 444 insertions(+), 9 deletions(-) create mode 100644 frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/__snapshots__/create-rs.test.ts.snap create mode 100644 frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/create-rs.test.ts diff --git a/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/__snapshots__/create-rs.test.ts.snap b/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/__snapshots__/create-rs.test.ts.snap new file mode 100644 index 00000000000..3785d747197 --- /dev/null +++ b/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/__snapshots__/create-rs.test.ts.snap @@ -0,0 +1,74 @@ +exports[`Create RS with shortest possible path > When the users create, modify and delete a RS, everything should work #0`] = +{ + "comment": "", + "definition": { + "customization": { + "field_names": [ + { + "mapping": { + "code": "country_code" + }, + "parent_type": "Continent", + "prefix": "prefix_", + "suffix": "_suffix" + } + ], + "root_fields_namespace": "namespace_", + "type_names": { + "mapping": { + "Country": "country_name" + }, + "prefix": "prefix_", + "suffix": "_suffix" + } + }, + "forward_client_headers": true, + "headers": [ + { + "name": "user_id", + "value": "1234" + } + ], + "timeout_seconds": 80, + "url": "https://countries.trevorblades.com/" + }, + "name": "remote_schema_name" +}; + +exports[`Create RS with longest possible path > When the users create, modify and delete a RS, everything should work #0`] = +{ + "comment": "", + "definition": { + "customization": { + "field_names": [ + { + "mapping": {}, + "parent_type": "query_root", + "prefix": "prefix_query_root", + "suffix": "query_root_suffix" + }, + { + "mapping": {}, + "parent_type": "mutation_root", + "prefix": "prefix_mutation_root", + "suffix": "mutation_root_suffix" + } + ], + "root_fields_namespace": "namespace_", + "type_names": { + "mapping": {}, + "prefix": "prefix_", + "suffix": "_suffix" + } + }, + "headers": [ + { + "name": "user_id", + "value": "1234" + } + ], + "timeout_seconds": 60, + "url": "https://countries.trevorblades.com/" + }, + "name": "remote_schema_name" +}; diff --git a/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/create-rs.test.ts b/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/create-rs.test.ts new file mode 100644 index 00000000000..ede40aeb72b --- /dev/null +++ b/frontend/apps/console-ce-e2e/src/e2e/remote-schemas/create-remote-schema/create-rs.test.ts @@ -0,0 +1,337 @@ +import { HasuraMetadataV3 } from '@hasura/console-legacy-ce'; +import { readMetadata } from '../../actions/withTransform/utils/services/readMetadata'; + +describe('Create RS with shortest possible path', () => { + it('When the users create, modify and delete a RS, everything should work', () => { + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**--- Step 1: Create a RS with shortest path**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + + cy.visit('/remote-schemas/manage/schemas', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + // -------------------- + cy.log('**--- Click on the Add button of the RS panel**'); + cy.get('[data-testid=data-create-remote-schemas]').click(); + + // RS name + cy.log('**--- Type the RS name**'); + cy.get('[name=name]').type('remote_schema_name'); + + // provide webhook URL + cy.log('**--- Add webhook url'); + cy.get('[name="url.value"]').type('https://graphql-pokemon2.vercel.app'); + + // click on create button to save ET + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('add_remote_schema')) { + req.alias = 'addRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('add_remote_schema')) { + req.alias = 'addRs'; + } + }); + cy.log('**--- Click on Add Remote Schema'); + cy.findByRole('button', { name: 'Add Remote Schema' }).click(); + cy.wait('@addRs'); + + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**--- Step 2: Modify RS to longest path and save it**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + + // go to modify tab of RS + cy.visit('/remote-schemas/manage/remote_schema_name/modify', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + // edit RS webhook url + cy.log('**--- Modify the webhoook URL'); + cy.get('[name=handler]') + .clear() + .type('https://countries.trevorblades.com/'); + + // check forward client header + cy.log('**--- Check forward client header'); + cy.findByText('Forward all headers from client').click(); + + // add header + cy.log('**--- Click on Add headers button and add some headers'); + cy.findAllByPlaceholderText('header name').type('user_id'); + cy.findAllByPlaceholderText('header value').type('1234'); + + // add server timeout + cy.log('**--- Add the gql server timeout'); + cy.get('[name=timeout_sec]').clear().type('80'); + + // click on create button to save ET + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + }); + cy.log('**--- Click on Add Remote Schema'); + cy.findByRole('button', { name: 'Save' }).click(); + cy.wait('@updateRs'); + + // to again to modif tab + cy.visit('/remote-schemas/manage/remote_schema_name/modify', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + // add gql customization + cy.log('**--- Click on Edit and apply some customization'); + cy.findByRole('button', { name: 'Edit' }).click(); + cy.get(`[name=namespace]`).type('namespace_'); + cy.get(`[name=prefix]`).type('prefix_'); + cy.get(`[name=suffix]`).type('_suffix'); + cy.get('[name=type-name-lhs ]').select('Country'); + cy.get(`[name="type-name-rhs[0]"]`).type('country_name'); + cy.findByRole('button', { name: 'Add Field Mapping' }).click(); + cy.get('[name=field-type]').select('Continent'); + cy.get(`[name=field-type-prefix]`).type('prefix_'); + cy.get(`[name=field-type-suffix]`).type('_suffix'); + cy.get('[name=field-type-lhs]').select('code'); + cy.get(`[name="field-type-rhs[0]"]`).type('country_code'); + cy.findByRole('button', { name: 'Add Field Customization' }).click(); + + // save the RS + cy.log('**--- Click on Save to modify the RS'); + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + }); + cy.findByRole('button', { name: 'Save' }).click(); + cy.wait('@updateRs'); + + cy.visit('/remote-schemas/manage/remote_schema_name/modify', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + readMetadata().then((md: { body: HasuraMetadataV3 }) => { + cy.wrap( + md.body?.remote_schemas?.find(rs => rs?.name === 'remote_schema_name') + ).toMatchSnapshot({ name: 'Modify the shotest path to longest' }); + }); + + // delete RS + cy.log('**--- Click on Delete to delete the RS'); + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('remove_remote_schema')) { + req.alias = 'removeRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('remove_remote_schema')) { + req.alias = 'removeRs'; + } + }); + cy.findByRole('button', { name: 'Delete' }).click(); + cy.wait('@removeRs'); + }); +}); + +describe('Create RS with longest possible path', () => { + it('When the users create, modify and delete a RS, everything should work', () => { + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**--- Step 1: Create a RS with longest path**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + + cy.visit('/remote-schemas/manage/schemas', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + // -------------------- + cy.log('**--- Click on the Add button of the RS panel**'); + cy.get('[data-testid=data-create-remote-schemas]').click(); + + // RS name + cy.log('**--- Type the RS name**'); + cy.get('[name="name"]').type('remote_schema_name'); + + // add comment + cy.log('**--- Add comment to RS**'); + cy.get(`[name=comment]`).type('RS comment'); + + // provide webhook URL + cy.log('**--- Add webhook url'); + cy.get('[name="url.value"]').type('https://graphql-pokemon2.vercel.app'); + + // add server timeout + cy.log('**--- Add the gql server timeout'); + cy.get('[name=timeout_seconds]').type('80'); + + // check forward client header + cy.log('**--- Check forward client header'); + cy.get('[name=forward_client_headers]').click(); + + // add header + cy.log('**--- Click on Add headers button and add some headers'); + cy.findByRole('button', { name: 'Add additional headers' }).click(); + cy.get(`[name="headers[0].name"]`).type('user_id'); + cy.get(`[name="headers[0].value"]`).type('1234'); + + // add gql customization + cy.log('**--- Click on Add GQL Customization and apply some customization'); + cy.findByRole('button', { name: 'Add GQL Customization' }).click(); + cy.get(`[name="customization.root_fields_namespace"]`).type('namespace_'); + cy.get(`[name="customization.type_prefix"]`).type('prefix_'); + cy.get(`[name="customization.type_suffix"]`).type('_suffix'); + cy.get(`[name="customization.query_root.parent_type"]`).type('query_root'); + cy.get(`[name="customization.query_root.prefix"]`).type( + 'prefix_query_root' + ); + cy.get(`[name="customization.query_root.suffix"]`).type( + 'query_root_suffix' + ); + cy.get(`[name="customization.mutation_root.parent_type"]`).type( + 'mutation_root' + ); + cy.get(`[name="customization.mutation_root.prefix"]`).type( + 'prefix_mutation_root' + ); + cy.get(`[name="customization.mutation_root.suffix"]`).type( + 'mutation_root_suffix' + ); + + // click on create button to save ET + + cy.log('**--- Click on Add Remote Schema'); + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('add_remote_schema')) { + req.alias = 'addRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('add_remote_schema')) { + req.alias = 'addRs'; + } + }); + cy.findByRole('button', { name: 'Add Remote Schema' }).click(); + cy.wait('@addRs'); + + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**--- Step 2: Modify RS to shortest path and save it**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + cy.log('**------------------------------**'); + + // go to modify tab of RS + cy.visit('/remote-schemas/manage/remote_schema_name/modify', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + // edit RS webhook url + cy.log('**--- Modify the webhoook URL'); + cy.get('[name=handler]') + .clear() + .type('https://countries.trevorblades.com/'); + + // check forward client header + cy.log('**--- Check forward client header'); + cy.findByText('Forward all headers from client').click(); + + // clear gql timeout + cy.log('**--- Clear the gql time out'); + cy.get('[name=timeout_sec]').clear(); + + // clear comment + cy.log('**--- Clear the RS comment'); + cy.get('[name=comment]').clear(); + + // click on save button to save ET + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('update_remote_schema')) { + req.alias = 'updateRs'; + } + }); + cy.log('**--- Click on Add Remote Schema'); + cy.findByRole('button', { name: 'Save' }).click(); + cy.wait('@updateRs'); + + cy.visit('/remote-schemas/manage/remote_schema_name/modify', { + timeout: 10000, + onBeforeLoad(win) { + cy.stub(win, 'prompt').returns('remote_schema_name'); + }, + }); + + readMetadata().then((md: { body: HasuraMetadataV3 }) => { + cy.wrap( + md.body?.remote_schemas?.find(rs => rs?.name === 'remote_schema_name') + ).toMatchSnapshot({ name: 'Modify the shotest path to longest' }); + }); + + // delete RS + cy.log('**--- Click on Delete to delete the RS'); + cy.intercept('POST', 'http://localhost:8080/v1/metadata', req => { + if (JSON.stringify(req.body).includes('remove_remote_schema')) { + req.alias = 'removeRs'; + } + req.continue(); + }); + cy.intercept('POST', 'http://localhost:9693/apis/migrate', req => { + if (JSON.stringify(req.body).includes('remove_remote_schema')) { + req.alias = 'removeRs'; + } + }); + cy.findByRole('button', { name: 'Delete' }).click(); + cy.wait('@removeRs'); + }); +}); diff --git a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/Common.js b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/Common.js index 32842086e64..6566e864445 100644 --- a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/Common.js +++ b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/Common.js @@ -117,6 +117,7 @@ class Common extends React.Component { data-test="remote-schema-timeout-conf" pattern="^\d+$" title="Only non negative integers are allowed" + name="timeout_sec" /> @@ -247,6 +248,7 @@ class Common extends React.Component { placeholder="Comment" value={comment} data-key="comment" + name="comment" onChange={this.handleInputChange.bind(this)} disabled={isDisabled} data-test="remote-schema-comment" diff --git a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/FieldNames.tsx b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/FieldNames.tsx index 716c5a5250d..6c7ceaa3fb1 100644 --- a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/FieldNames.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/FieldNames.tsx @@ -45,6 +45,7 @@ const SelectOne = ({ onChange={onChange} className={inputStyles} data-test={label} + name={label} > {[...options].sort().map((op, i) => ( @@ -93,7 +94,7 @@ const FieldNames = ({ parentType: e.target.value, }); }} - label={`remote-schema-customization-${label}-parent-type-input`} + label={label} /> @@ -113,6 +114,7 @@ const FieldNames = ({ }) } data-test={`remote-schema-customization-${label}-field-prefix-input`} + name={`${label}-prefix`} /> @@ -132,6 +134,7 @@ const FieldNames = ({ }) } data-test={`remote-schema-customization-${label}-field-suffix-input`} + name={`${label}-suffix`} /> diff --git a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/GraphQLCustomizationEdit.tsx b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/GraphQLCustomizationEdit.tsx index a71adc4f83a..879a7246562 100644 --- a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/GraphQLCustomizationEdit.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/GraphQLCustomizationEdit.tsx @@ -161,6 +161,7 @@ const GraphQLCustomizationEdit = ({ type="text" className={inputStyles} placeholder="namespace_" + name="namespace" value={rootFieldNamespace || ''} data-test="remote-schema-customization-root-field-input" onChange={e => @@ -182,6 +183,7 @@ const GraphQLCustomizationEdit = ({ type="text" className={inputStyles} placeholder="prefix_" + name="prefix" value={typeNames?.prefix || ''} data-test="remote-schema-customization-type-name-prefix-input" onChange={e => @@ -204,6 +206,7 @@ const GraphQLCustomizationEdit = ({ type="text" className={inputStyles} placeholder="_suffix" + name="suffix" value={typeNames?.suffix || ''} data-test="remote-schema-customization-type-name-suffix-input" onChange={e => diff --git a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/TypeMapping.tsx b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/TypeMapping.tsx index 3a10636c48e..4f5aa8afa1e 100644 --- a/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/TypeMapping.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/components/Services/RemoteSchema/Common/GraphQLCustomization/TypeMapping.tsx @@ -27,6 +27,7 @@ const SelectOne = ({ onChange={onChange} className={`${inputStyles} font-normal`} data-test={`remote-schema-customization-${label}-lhs-input`} + name={`${label}-lhs`} >