Skip to content

Commit

Permalink
form builder covered with e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dsheiko committed Dec 17, 2018
1 parent 75914ee commit cfac832
Show file tree
Hide file tree
Showing 21 changed files with 202 additions and 41 deletions.
9 changes: 6 additions & 3 deletions jest.cfg.e2e.js
@@ -1,10 +1,13 @@
module.exports = {
verbose: true,
testEnvironment: "node",

testRegex: "src/__e2e__/specs/.+\\.spec\\.js$",
setupFiles: [
"./jest.setup.js"
],
testRegex: "src/__e2e__/specs/.+\\.spec\\.jsx?$",
moduleFileExtensions: [
"js"
"js",
"jsx"
],
modulePaths: [
"src",
Expand Down
29 changes: 26 additions & 3 deletions src/__e2e__/lib/bootstrap.js
Expand Up @@ -5,20 +5,23 @@ const { Application } = require( "spectron" ),
ROOT_PATH = join( __dirname, "..", "..", ".." ),
shell = require( "shelljs" ),
DIST_PATH = join( ROOT_PATH, "dist" ),
SCREENSHOT_PATH = join( __dirname, "..", "screenshots" ),
manifest = require( join( ROOT_PATH, "package.json" ) ),
APP_PATH = process.platform === "win32" ? join( DIST_PATH, "win-unpacked", "puppetry.exe" ) :
( process.platform === "darwin" ? join( DIST_PATH, "mac", "puppetry.app", "Contents", "MacOS", "puppetry" )
: join( DIST_PATH, "linux-unpacked", "puppetry" ) );

shell.config.fatal = true;

shell.mkdir( "-p" , join( __dirname, "..", "screenshots" ) );
shell.mkdir( "-p" , SCREENSHOT_PATH );

class Ctx {

constructor() {
this.app = null;
this.tmpDir = {};
this.ns = "";
this.counter = 1;
}

async startApp() {
Expand All @@ -38,8 +41,10 @@ class Ctx {
}

async screenshot( name ) {
const buf = await this.app.browserWindow.capturePage();
fs.writeFileSync( join( __dirname, "..", "screenshots", `${ name }.png` ), buf );
const dir = join( SCREENSHOT_PATH, this.ns ),
buf = await this.app.browserWindow.capturePage();
shell.mkdir( "-p" , dir );
fs.writeFileSync( join( dir, `${ this.counter++ }--${ name }.png` ), buf );
}

async waitUntilLayoutUpdates() {
Expand All @@ -64,6 +69,24 @@ class Ctx {
return await this.app.client.isExisting( ".critical-error" );
}

async checkLogErrors() {
const logs = await this.app.client.getRenderProcessLogs();
logs.forEach( log => {
if ( log.level === "SEVERE" ) {
console.error( "console.error", log.message );
expect( log.level ).not.toEqual( "SEVERE" );
}
});
}

async select( selector, value ) {
await this.app.client.click( `${ selector } .ant-select-selection--single` );
await this.app.client.pause( 100 );
await this.app.client.setValue( `${ selector } input.ant-select-search__field`, value );
await this.app.client.keys([ "Enter" ]);
await this.app.client.pause( 100 );
}

createTmpDir( key ) {
this.tmpDir[ key ] = tmp.dirSync().name;
}
Expand Down
5 changes: 4 additions & 1 deletion src/__e2e__/lib/constants.js
Expand Up @@ -2,4 +2,7 @@ exports.MODAL_CLOSE_ICON = `button.ant-modal-close`;
exports.MODAL_CANCEL_BTN = `.btn--modal-cancel`;
exports.MODAL_OK_BTN = `.btn--modal-ok`;
exports.MODAL_NEW_PROJECT = `.c-new-project-modal`;
exports.MODAL_NEW_SUITE = `.c-new-suite-modal`;
exports.MODAL_NEW_SUITE = `.c-new-suite-modal`;
exports.ACTIVE_EDITABLE_ROW = `.ant-form.ant-form-horizontal.cell-form`;
exports.EDITABLE_ROW_SUBMIT_BTN = `.ant-btn.ant-btn-primary`;
exports.EDITABLE_ROW_EXPAND_ICON = `.ant-table-row-expand-icon.ant-table-row-collapsed`;
13 changes: 9 additions & 4 deletions src/__e2e__/specs/firstLaunch.spec.js
Expand Up @@ -8,20 +8,25 @@ describe( "First launch", () => {

beforeAll( async () => {
await ctx.startApp();
ctx.ns = "first-launch";
});

afterAll( async () => {
await ctx.stopApp();
});

afterEach( async() => {
await ctx.checkLogErrors();
});

describe( "Welcome screen", () => {

test( "app shows welcome page", async () => {
const win = ctx.app.browserWindow;
expect( await win.isVisible() ).toBeTruthy();
expect( await ctx.client.isExisting( "#cWelcome" ) ).toBeTruthy();
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "welcome-page" );
await ctx.screenshot( "welcome-screen" );
});

test( "toolbar does not have project name", async () => {
Expand All @@ -41,11 +46,11 @@ describe( "First launch", () => {
await ctx.client.click( "#cWelcomeNewProjectBtn" );
await ctx.client.pause( 300 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "welcome--new-project" );
await ctx.screenshot( "new-project-modal" );
expect( await ctx.client.isExisting( ".c-new-project-modal" ) ).toBeTruthy();
await ctx.client.click( `.c-new-project-modal ${ S.MODAL_CLOSE_ICON }` );
await ctx.client.pause( 300 );
await ctx.screenshot( "welcome--new-project-closed" );
await ctx.screenshot( "new-project-closed" );
});
});

Expand All @@ -56,7 +61,7 @@ describe( "First launch", () => {
await ctx.client.waitForExist( "#cMain" );
await ctx.waitUntilLayoutUpdates();
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "welcome--demo-project" );
await ctx.screenshot( "demo-project-screen" );
});
});

Expand Down
115 changes: 103 additions & 12 deletions src/__e2e__/specs/newProject.spec.js
@@ -1,6 +1,8 @@
const { Ctx } = require( "../lib/bootstrap" ),
S = require( "../lib/constants" ),
ctx = new Ctx();
{ schema } = require( "../../component/Schema/schema.jsx" ),
ctx = new Ctx(),
FIX_TARGET = "SEL_FOO";

jest.setTimeout( 50000 );

Expand All @@ -9,19 +11,23 @@ describe( "New Project", () => {

beforeAll( async () => {
await ctx.startApp();
ctx.ns = "new-project";
});

afterAll( async () => {
ctx.cleanupTmpDirs();
await ctx.stopApp();
});

afterEach( async() => {
await ctx.checkLogErrors();
});

test( "app opens New Project modal", async () => {
expect( await ctx.client.isExisting( "#cWelcome" ) ).toBeTruthy();
await ctx.client.click( "#cWelcomeNewProjectBtn" );
await ctx.client.pause( 300 );
await ctx.screenshot( "new-project-modal" );
await ctx.screenshot( "new-project-modal-opened" );
// New Project modal opens
expect( await ctx.client.isExisting( S.MODAL_NEW_PROJECT ) ).toBeTruthy();
});
Expand All @@ -38,7 +44,7 @@ describe( "New Project", () => {
await ctx.client.click( `${ S.MODAL_NEW_PROJECT } ${ S.MODAL_OK_BTN }` );
await ctx.client.pause( 300 );
expect( await ctx.client.isExisting( "#cInfo" ) ).toBeTruthy();
await ctx.screenshot( "new-project-lands-on-info-screen" );
await ctx.screenshot( "info-screen" );
});

test( "Project Info screen has create and open suite buttons", async () => {
Expand All @@ -63,12 +69,7 @@ describe( "New Project", () => {
await ctx.client.click( `${ S.MODAL_NEW_SUITE } ${ S.MODAL_OK_BTN }` );
await ctx.client.pause( 500 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-suite-created" );
// .c-tab-group-suite .ant-tabs-tab:first-child
// .c-tab-group-suite .ant-tabs-tab:last-child

// #cSuiteForm #title
// #cSuiteForm #timeout
await ctx.screenshot( "suite-screen" );
});

test( "modify suite form", async() => {
Expand All @@ -77,14 +78,104 @@ describe( "New Project", () => {
await ctx.client.click( `#cSuiteFormChangeBtn` );
await ctx.client.pause( 300 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-suite-form-modified" );
await ctx.screenshot( "suite-form-modified" );
});

test( "go tab Targets", async() => {
await ctx.client.click( `.c-tab-group-suite .ant-tabs-tab:first-child` );
await ctx.client.click( `#cMain .ant-tabs-tab:nth-child(1)` );
await ctx.client.pause( 500 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "goto-tab--targets" );
});

test( "add a target", async() => {
await ctx.client.click( `#cTargetTableAddBtn` );
await ctx.client.pause( 200 );
expect( await ctx.client.isExisting( "#cTargetTable .input--target > input" ) ).toBeTruthy();
expect( await ctx.client.isExisting( "#cTargetTable .input--selector > input" ) ).toBeTruthy();
await ctx.client.setValue( "#cTargetTable .input--target > input", FIX_TARGET );
await ctx.client.setValue( "#cTargetTable .input--selector > input", ".foo" );
await ctx.client.pause( 200 );
await ctx.client.click( `#cTargetTable ${ S.EDITABLE_ROW_SUBMIT_BTN }` );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-target" );
});

test( "go tab Groups", async() => {
await ctx.client.click( `#cMain .ant-tabs-tab:nth-child(2)` );
await ctx.client.pause( 500 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-suite-tab-targets" );
await ctx.screenshot( "goto-tab--groups" );
});

test( "add a group", async() => {
await ctx.client.click( `#cGroupTableAddBtn` );
await ctx.client.pause( 200 );
expect( await ctx.client.isExisting( "#cGroupTable .input--title > input" ) ).toBeTruthy();
await ctx.client.setValue( "#cGroupTable .input--title > input", "Test group" );
await ctx.client.pause( 200 );
await ctx.client.click( `#cGroupTable ${ S.EDITABLE_ROW_SUBMIT_BTN }` );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-suite" );
});

test( "expand group", async() => {
await ctx.client.click( `#cGroupTable ${ S.EDITABLE_ROW_EXPAND_ICON }` );
await ctx.screenshot( "group-expanded" );
});

test( "add a test", async() => {
await ctx.client.click( `#cTestTableAddBtn` );
await ctx.client.pause( 200 );
expect( await ctx.client.isExisting( "#cTestTable .input--title > input" ) ).toBeTruthy();
await ctx.client.setValue( "#cTestTable .input--title > input", "Test" );
await ctx.client.pause( 200 );
await ctx.client.click( `#cTestTable ${ S.EDITABLE_ROW_SUBMIT_BTN }` );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( "new-test" );
});

test( "expand test", async() => {
await ctx.client.click( `#cTestTable ${ S.EDITABLE_ROW_EXPAND_ICON }` );
await ctx.screenshot( "test-expanded" );
await ctx.client.pause( 200 );
});

test( "add a command", async() => {
await ctx.client.click( `#cCommandTableAddBtn` );
await ctx.client.pause( 200 );

});

test( "select target: page", async() => {
await ctx.select( "#cCommandForm .select--target", "page" );
await ctx.client.pause( 200 );
expect( await ctx.boundaryError() ).toBeFalsy();
});


Object.keys( schema.page ).forEach( method => {
test( `select page method: ${ method }`, async() => {
await ctx.select( "#cCommandForm .select--page-method", method );
await ctx.client.pause( 200 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( `new-command--select-${ method }` );
});
});

test( `select target: ${ FIX_TARGET }`, async() => {
await ctx.select( "#cCommandForm .select--target", FIX_TARGET );
await ctx.client.pause( 200 );
expect( await ctx.boundaryError() ).toBeFalsy();
});

Object.keys( schema.element ).forEach( method => {
test( `select element method: ${ method }`, async() => {
await ctx.select( "#cCommandForm .select--element-method", method );
await ctx.client.pause( 200 );
expect( await ctx.boundaryError() ).toBeFalsy();
await ctx.screenshot( `new-command--select-${ method }` );
});
});

});
4 changes: 3 additions & 1 deletion src/component/AppLayout/Main/EditableCell.jsx
Expand Up @@ -8,6 +8,7 @@ export class EditableCell extends React.Component {
static propTypes = {
dataIndex: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
className: PropTypes.string,
record: PropTypes.object.isRequired,
liftFormStateUp: PropTypes.func.isRequired,
updateRecord: PropTypes.func.isRequired,
Expand Down Expand Up @@ -51,7 +52,7 @@ export class EditableCell extends React.Component {
}

render() {
const { placeholder, dataIndex, record, prefixIcon } = this.props,
const { placeholder, dataIndex, record, prefixIcon, className } = this.props,
{ editing } = record,
error = this.state.error,
value = this.props.record[ dataIndex ];
Expand All @@ -68,6 +69,7 @@ export class EditableCell extends React.Component {
<Input
prefix={ prefixIcon || null }
defaultValue={value}
className={ className || null }
onChange={this.onChange}
placeholder={placeholder}
tabIndex={ dataIndex === "select" ? 2 : 1 }
Expand Down
5 changes: 4 additions & 1 deletion src/component/AppLayout/Main/GroupTable.jsx
Expand Up @@ -21,6 +21,7 @@ export class GroupTable extends AbstractEditableTable {
<EditableCell
prefixIcon={ recordPrefIcon }
record={ record }
className="input--title"
dataIndex="title"
placeholder="Describe target or scenario you want to test"
liftFormStateUp={ this.liftFormStateUp }
Expand Down Expand Up @@ -86,7 +87,9 @@ export class GroupTable extends AbstractEditableTable {
pagination={false}
onExpand={this.onExpand}
expandedRowRender={ this.renderExpandedTable }
footer={() => ( <Button onClick={ this.addRecord }><Icon type="plus" />Add a group</Button> )}
footer={() => ( <Button
id="cGroupTableAddBtn"
onClick={ this.addRecord }><Icon type="plus" />Add a group</Button> )}
/>
</ErrorBoundary>
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/component/AppLayout/Main/GroupTable/TestTable.jsx
Expand Up @@ -21,6 +21,7 @@ export class TestTable extends AbstractEditableTable {
render: ( text, record ) => (
<EditableCell
prefixIcon={ recordPrefIcon }
className="input--title"
record={ record }
dataIndex="title"
placeholder="Describe the assertions you want to perform"
Expand Down Expand Up @@ -79,6 +80,7 @@ export class TestTable extends AbstractEditableTable {
<ErrorBoundary>
<Table
className="draggable-table"
id="cTestTable"
components={this.components}
onRow={this.onRow}
rowClassName={ this.onRowClassName }
Expand All @@ -89,7 +91,9 @@ export class TestTable extends AbstractEditableTable {
columns={ this.columns }
onExpand={ this.onExpand }
pagination={ false }
footer={() => ( <Button onClick={ this.addRecord }><Icon type="plus" />Add a test</Button> )}
footer={() => ( <Button
id="cTestTableAddBtn"
onClick={ this.addRecord }><Icon type="plus" />Add a test</Button> )}
/>
</ErrorBoundary>
);
Expand Down
Expand Up @@ -67,6 +67,7 @@ export class CommandModal extends React.Component {
<InstantModal
visible={ isVisible }
title="Title"
id="cCommandModal"
onOk={this.onOK}
onCancel={this.onCancel}
footer={[
Expand Down

0 comments on commit cfac832

Please sign in to comment.