mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
478 lines
15 KiB
TypeScript
478 lines
15 KiB
TypeScript
import { dedent } from '../support/testkit';
|
|
|
|
const selectors = {
|
|
buttonGraphiQLPreflight: '[aria-label*="Preflight Script"]',
|
|
buttonModalCy: 'preflight-modal-button',
|
|
buttonToggleCy: 'toggle-preflight',
|
|
buttonHeaders: '[data-name="headers"]',
|
|
headersEditor: {
|
|
textArea: '.graphiql-editor-tool .graphiql-editor:last-child textarea',
|
|
},
|
|
graphiql: {
|
|
buttonExecute: '.graphiql-execute-button',
|
|
},
|
|
|
|
modal: {
|
|
buttonSubmitCy: 'preflight-modal-submit',
|
|
},
|
|
};
|
|
|
|
const data: { slug: string } = {
|
|
slug: '',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
cy.clearLocalStorage().then(async () => {
|
|
window.localStorage.setItem('hive:laboratory:type', 'graphiql');
|
|
|
|
cy.task('seedTarget').then(({ slug, refreshToken }: any) => {
|
|
cy.setCookie('sRefreshToken', refreshToken);
|
|
data.slug = slug;
|
|
cy.visit(`/${slug}/laboratory`);
|
|
cy.get(selectors.buttonGraphiQLPreflight).click();
|
|
});
|
|
});
|
|
});
|
|
|
|
/** Helper function for setting the text within a monaco editor as typing manually results in flaky tests */
|
|
function setMonacoEditorContents(editorCyName: string, text: string) {
|
|
// wait for textarea appearing which indicates monaco is loaded
|
|
cy.dataCy(editorCyName).find('textarea');
|
|
cy.window().then(win => {
|
|
// First, check if monaco is available on the main window
|
|
const editor = (win as any).monaco.editor
|
|
.getEditors()
|
|
.find(e => e.getContainerDomNode().parentElement.getAttribute('data-cy') === editorCyName);
|
|
|
|
// If Monaco instance is found
|
|
if (editor) {
|
|
editor.setValue(text);
|
|
} else {
|
|
throw new Error('Monaco editor not found on the window or frames[0]');
|
|
}
|
|
});
|
|
}
|
|
|
|
function setEditorScript(script: string) {
|
|
setMonacoEditorContents('preflight-editor', script);
|
|
}
|
|
|
|
describe('Laboratory > Preflight Script', () => {
|
|
// https://github.com/graphql-hive/console/pull/6450
|
|
it('regression: loads even if local storage is set to {}', () => {
|
|
window.localStorage.setItem('hive:laboratory:environment', '{}');
|
|
cy.visit(`/${data.slug}/laboratory`);
|
|
cy.get(selectors.buttonGraphiQLPreflight).click();
|
|
});
|
|
it('mini script editor is read only', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
// Wait loading disappears
|
|
cy.dataCy('preflight-editor-mini').should('not.contain', 'Loading');
|
|
// Click
|
|
cy.dataCy('preflight-editor-mini').click();
|
|
// And type
|
|
cy.dataCy('preflight-editor-mini').within(() => {
|
|
cy.get('textarea').type('🐝', { force: true });
|
|
});
|
|
cy.dataCy('preflight-editor-mini').should('have.text', 'Cannot edit in read-only editor');
|
|
});
|
|
});
|
|
|
|
describe('Preflight Script Modal', () => {
|
|
const script = 'console.log("Hello_world")';
|
|
const env = '{"foo":123}';
|
|
|
|
beforeEach(() => {
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents('env-editor', env);
|
|
});
|
|
|
|
it('save script and environment variables when submitting', () => {
|
|
setEditorScript(script);
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
cy.dataCy('env-editor-mini').should('have.text', env);
|
|
cy.dataCy('toggle-preflight').click();
|
|
cy.dataCy('preflight-editor-mini').should('have.text', script);
|
|
cy.reload();
|
|
cy.get('[aria-label*="Preflight Script"]').click();
|
|
cy.dataCy('env-editor-mini').should('have.text', env);
|
|
cy.dataCy('preflight-editor-mini').should('have.text', script);
|
|
});
|
|
|
|
it('logs show console/error information', () => {
|
|
setEditorScript(script);
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
|
|
setEditorScript(
|
|
`console.info(1)
|
|
console.warn(true)
|
|
console.error('Fatal')
|
|
throw new TypeError('Test')`,
|
|
);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
// First log previous log message
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
// After the new logs
|
|
cy.dataCy('console-output').should(
|
|
'contain',
|
|
['info: 1 (1:1)', 'warn: true (2:1)', 'error: Fatal (3:1)', 'error: Test (4:7)'].join(''),
|
|
);
|
|
});
|
|
|
|
it('prompt and pass the awaited response', () => {
|
|
setEditorScript(script);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
|
|
setEditorScript(
|
|
dedent`
|
|
const username = await lab.prompt('Enter your username');
|
|
console.info(username);
|
|
`,
|
|
);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('prompt').get('input').type('test-username');
|
|
cy.dataCy('prompt').get('form').submit();
|
|
|
|
// First log previous log message
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
// After the new logs
|
|
cy.dataCy('console-output').should(
|
|
'contain',
|
|
dedent`
|
|
info: test-username (2:1)
|
|
`,
|
|
);
|
|
});
|
|
|
|
it('prompt and cancel', () => {
|
|
setEditorScript(script);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
|
|
setEditorScript(
|
|
dedent`
|
|
const username = await lab.prompt('Enter your username');
|
|
console.info(username);
|
|
`,
|
|
);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('prompt').get('input').type('test-username');
|
|
cy.dataCy('prompt').get('[data-cy="prompt-cancel"]').click();
|
|
|
|
// First log previous log message
|
|
cy.dataCy('console-output').should('contain', 'log: Hello_world (1:1)');
|
|
// After the new logs
|
|
cy.dataCy('console-output').should(
|
|
'contain',
|
|
dedent`
|
|
info: null (2:1)
|
|
`,
|
|
);
|
|
});
|
|
|
|
it('script execution updates environment variables', () => {
|
|
setEditorScript(`lab.environment.set('my-test', "TROLOLOL")`);
|
|
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('env-editor').should(
|
|
'include.text',
|
|
// replace space with
|
|
'{ "foo": 123, "my-test": "TROLOLOL"}'.replaceAll(' ', '\xa0'),
|
|
);
|
|
});
|
|
|
|
it('`crypto-js` can be used for generating hashes', () => {
|
|
setEditorScript('console.log(lab.CryptoJS.SHA256("🐝"))');
|
|
cy.dataCy('run-preflight').click();
|
|
cy.dataCy('console-output').should('contain', 'info: Using crypto-js version:');
|
|
cy.dataCy('console-output').should(
|
|
'contain',
|
|
'log: d5b51e79e4be0c4f4d6b9a14e16ca864de96afe68459e60a794e80393a4809e8',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Execution', () => {
|
|
it('result.request.headers are added to the graphiql request base headers', () => {
|
|
// Setup Preflight Script
|
|
const preflightHeaders = {
|
|
foo: 'bar',
|
|
};
|
|
cy.dataCy(selectors.buttonToggleCy).click();
|
|
cy.dataCy(selectors.buttonModalCy).click();
|
|
setEditorScript(`lab.request.headers.append('foo', '${preflightHeaders.foo}')`);
|
|
cy.dataCy(selectors.modal.buttonSubmitCy).click();
|
|
// Run GraphiQL
|
|
cy.intercept({ headers: preflightHeaders }).as('request');
|
|
cy.get(selectors.graphiql.buttonExecute).click();
|
|
cy.wait('@request');
|
|
});
|
|
|
|
it('result.request.headers take precedence over graphiql request base headers', () => {
|
|
// Integrity Check: Ensure the header we think we're overriding is actually there to override.
|
|
// We achieve this by asserting a sent GraphiQL request includes the certain header and assume
|
|
// if its there once its there every time.
|
|
const baseHeaders = {
|
|
accept: 'application/json, multipart/mixed',
|
|
};
|
|
// Wait for GraphiQL editor to be ready before clicking execute
|
|
cy.get('.graphiql-query-editor .cm-s-graphiql').should('exist');
|
|
cy.intercept('POST', '**/api/lab/**').as('integrityCheck');
|
|
cy.get(selectors.graphiql.buttonExecute).click();
|
|
cy.wait('@integrityCheck').its('request.headers.accept').should('include', baseHeaders.accept);
|
|
// Setup Preflight Script
|
|
const preflightHeaders = {
|
|
accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8',
|
|
};
|
|
cy.dataCy(selectors.buttonToggleCy).click();
|
|
cy.dataCy(selectors.buttonModalCy).click();
|
|
setEditorScript(`lab.request.headers.append('accept', '${preflightHeaders.accept}')`);
|
|
cy.dataCy(selectors.modal.buttonSubmitCy).click();
|
|
// Run GraphiQL
|
|
cy.intercept({ headers: preflightHeaders }).as('request');
|
|
cy.get(selectors.graphiql.buttonExecute).click();
|
|
cy.wait('@request', { timeout: 10_000 });
|
|
});
|
|
|
|
it('result.request.headers are NOT substituted with environment variables', () => {
|
|
const barEnVarInterpolation = '{{bar}}';
|
|
// Setup Static Headers
|
|
const staticHeaders = {
|
|
foo_static: barEnVarInterpolation,
|
|
};
|
|
cy.get(selectors.buttonHeaders).click();
|
|
cy.get(selectors.headersEditor.textArea).type(JSON.stringify(staticHeaders), {
|
|
force: true,
|
|
parseSpecialCharSequences: false,
|
|
});
|
|
// Setup Preflight Script
|
|
const environmentVariables = {
|
|
bar: 'BAR_VALUE',
|
|
};
|
|
const preflightHeaders = {
|
|
foo_preflight: barEnVarInterpolation,
|
|
};
|
|
cy.dataCy(selectors.buttonToggleCy).click();
|
|
cy.dataCy(selectors.buttonModalCy).click();
|
|
setEditorScript(`
|
|
lab.environment.set('bar', '${environmentVariables.bar}')
|
|
lab.request.headers.append('foo_preflight', '${preflightHeaders.foo_preflight}')
|
|
`);
|
|
cy.dataCy(selectors.modal.buttonSubmitCy).click();
|
|
// Run GraphiQL
|
|
cy.intercept({
|
|
headers: {
|
|
...preflightHeaders,
|
|
foo_static: environmentVariables.bar,
|
|
},
|
|
}).as('request');
|
|
cy.get(selectors.graphiql.buttonExecute).click();
|
|
cy.wait('@request', { timeout: 10_000 });
|
|
});
|
|
|
|
it('header placeholders are substituted with environment variables', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
cy.get('[data-name="headers"]').click();
|
|
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
|
|
'{ "__test": "{{foo}} bar {{nonExist}}" }',
|
|
{
|
|
force: true,
|
|
parseSpecialCharSequences: false,
|
|
},
|
|
);
|
|
setMonacoEditorContents('env-editor-mini', '{"foo":"injected"}');
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
headers: {
|
|
__test: 'injected bar {{nonExist}}',
|
|
},
|
|
}).as('post');
|
|
cy.get('.graphiql-execute-button').click();
|
|
cy.wait('@post');
|
|
});
|
|
|
|
it('executed script updates update env editor and substitute headers', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
cy.get('[data-name="headers"]').click();
|
|
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
|
|
'{ "__test": "{{foo}}" }',
|
|
{
|
|
force: true,
|
|
parseSpecialCharSequences: false,
|
|
},
|
|
);
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents('preflight-editor', `lab.environment.set('foo', '92')`);
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
headers: {
|
|
__test: '92',
|
|
},
|
|
}).as('post');
|
|
cy.get('.graphiql-execute-button').click();
|
|
cy.wait('@post');
|
|
});
|
|
|
|
it('execute, prompt and use it in headers', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
|
|
cy.get('[data-name="headers"]').click();
|
|
cy.get('[data-name="headers"]').click();
|
|
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
|
|
'{ "__test": "{{username}}" }',
|
|
{
|
|
force: true,
|
|
parseSpecialCharSequences: false,
|
|
},
|
|
);
|
|
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents(
|
|
'preflight-editor',
|
|
dedent`
|
|
const username = await lab.prompt('Enter your username');
|
|
lab.environment.set('username', username);
|
|
`,
|
|
);
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
headers: {
|
|
__test: 'foo',
|
|
},
|
|
}).as('post');
|
|
cy.get('.graphiql-execute-button').click();
|
|
|
|
cy.dataCy('prompt').get('input').type('foo');
|
|
cy.dataCy('prompt').get('form').submit();
|
|
|
|
cy.wait('@post');
|
|
});
|
|
|
|
it('disabled script is not executed', () => {
|
|
cy.get('[data-name="headers"]').click();
|
|
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
|
|
'{ "__test": "{{foo}}" }',
|
|
{
|
|
force: true,
|
|
parseSpecialCharSequences: false,
|
|
},
|
|
);
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents('preflight-editor', `lab.environment.set('foo', 92)`);
|
|
setMonacoEditorContents('env-editor', `{"foo":10}`);
|
|
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
headers: {
|
|
__test: '10',
|
|
},
|
|
}).as('post');
|
|
cy.get('.graphiql-execute-button').click();
|
|
cy.wait('@post');
|
|
});
|
|
|
|
it('logs are visible when opened', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents(
|
|
'preflight-editor',
|
|
dedent`
|
|
console.info(1)
|
|
console.warn(true)
|
|
console.error('Fatal')
|
|
throw new TypeError('Test')
|
|
`,
|
|
);
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
}).as('post');
|
|
|
|
// shows no logs before executing
|
|
cy.get('#preflight-logs button[data-cy="trigger"]').click({
|
|
// it's because the button is not fully visible on the screen
|
|
force: true,
|
|
});
|
|
cy.get('#preflight-logs [data-cy="logs"]').should(
|
|
'contain',
|
|
['No logs available', 'Execute a query to see logs'].join(''),
|
|
);
|
|
|
|
cy.get('.graphiql-execute-button').click();
|
|
cy.wait('@post');
|
|
|
|
cy.get('#preflight-logs [data-cy="logs"]').should(
|
|
'contain',
|
|
[
|
|
'log: Running script...',
|
|
'info: 1 (1:1)',
|
|
'warn: true (2:1)',
|
|
'error: Fatal (3:1)',
|
|
'error: Test (4:7)',
|
|
'log: Script failed',
|
|
].join(''),
|
|
);
|
|
});
|
|
|
|
it('logs are cleared when requested', () => {
|
|
cy.dataCy('toggle-preflight').click();
|
|
|
|
cy.dataCy('preflight-modal-button').click();
|
|
setMonacoEditorContents(
|
|
'preflight-editor',
|
|
dedent`
|
|
console.info(1)
|
|
console.warn(true)
|
|
console.error('Fatal')
|
|
throw new TypeError('Test')
|
|
`,
|
|
);
|
|
cy.dataCy('preflight-modal-submit').click();
|
|
|
|
cy.intercept({
|
|
method: 'POST',
|
|
}).as('post');
|
|
cy.get('.graphiql-execute-button').click();
|
|
cy.wait('@post');
|
|
|
|
// open logs
|
|
cy.get('#preflight-logs button[data-cy="trigger"]').click({
|
|
// it's because the button is not fully visible on the screen
|
|
force: true,
|
|
});
|
|
|
|
cy.get('#preflight-logs [data-cy="logs"]').should(
|
|
'contain',
|
|
[
|
|
'log: Running script...',
|
|
'info: 1 (1:1)',
|
|
'warn: true (2:1)',
|
|
'error: Fatal (3:1)',
|
|
'error: Test (4:7)',
|
|
'log: Script failed',
|
|
].join(''),
|
|
);
|
|
|
|
cy.get('#preflight-logs button[data-cy="erase-logs"]').click();
|
|
cy.get('#preflight-logs [data-cy="logs"]').should(
|
|
'contain',
|
|
['No logs available', 'Execute a query to see logs'].join(''),
|
|
);
|
|
});
|
|
});
|