//@param { bool } exitWithEsc : true to exit by pressing esc, false to click on the button async closeViewer(exitWithEsc) { await t.hover(selectors.viewerWrapper) await isExistingAndVisibile(selectors.viewerBtnClose, 'Close button') exitWithEsc ? await t.pressKey('esc') : await t.click(selectors.viewerBtnClose) }
//@param {String} screenshotPath : path for screenshots taken in this test //@param {number} startIndex : index of the 1st file to open //@param {number} numberOfNavigation : the number of file we want to go through during the test. async navigateInViewer({ screenshotPath: screenshotPath, startIndex: startIndex, numberOfNavigation: numberOfNavigation }) { console.log( `startIndex : ${startIndex} / numberOfNavigation : ${numberOfNavigation}` ) for (let i = startIndex; i < startIndex + numberOfNavigation; i++) { await this.navigateToNextFile(i) //navigateToNextFile brings you on the next file, so we are sure there is a Previous Button on this image await t.hover(selectors.btnViewerNavPrevious, { offsetX: 0, offsetY: 0 }) if (t.fixtureCtx.isVR) await t.fixtureCtx.vr.takeScreenshotAndUpload({ screenshotPath: `${screenshotPath}-${i}-next` }) } for (let i = startIndex + numberOfNavigation - 1; i > startIndex; i--) { console.log(` i : ${i} `) await this.navigateToPrevFile(i) await t.hover(selectors.btnViewerNavNext, { offsetX: 0, offsetY: 0 }) if (t.fixtureCtx.isVR) await t.fixtureCtx.vr.takeScreenshotAndUpload({ screenshotPath: `${screenshotPath}-${i}-prev` }) } }
test('String ctor argument', async() => { const el1 = await Selector('#htmlElement')(); const el2 = await Selector('.svg1')(); await t.expect(el1.tagName).eql('div'); await t.expect(el2.tagName).eql('rect'); });
test('Selector "filter" method', async() => { // String filter await t.expect(await Selector('body div').filter('#htmlElementWithInnerText').id).eql('htmlElementWithInnerText'); // Function filter await t.expect(await Selector('#container div').filter(node => node.id === 'el3').id).eql('el3'); // Compound await t.expect(await Selector('div').filter('.common').filter('.class1').id).eql('common2'); // Parameterized selector const withClass = Selector(className => document.getElementsByClassName(className)); await t.expect(await withClass('common').filter('.class1').id).eql('common2'); // With other filters await t.expect(await Selector('div').filter('.common').nth(0).id).eql('common1'); // Should not apply implicit index filter when used as transitive selector let label = Selector('#list *').filter('label'); await t.expect(await label.filter('#release').id).eql('release'); await t.expect(await label.filter('#write').id).eql('write'); // Should apply explicit index filter when used as transitive selector label = Selector('#list *').filter('label'); await t.expect(await label.nth(0).parent(0).find('#release').exists).notOk(); await t.expect(await label.nth(1).parent(0).find('#release').exists).notOk(); await t.expect(await label.nth(2).parent(0).find('#release').exists).ok(); });
//download using the common download button async checkCommonViewerDownload() { await t.hover(selectors.viewerWrapper) await isExistingAndVisibile( selectors.btnDownloadViewerToolbar, 'Download button in toolbar' ) await t .setNativeDialogHandler(() => true) .click(selectors.btnDownloadViewerToolbar) }
//@param { path } screenshotPath - mandatory //@param { mask (or false) } withMask : set a mask for screenshot //@param { selector } selector : set if we want a screenshot on an element rather than the whole page //@param { interger (ms) } delay //@param { page } pageToWait : when using delay, the current page is reload so we need a page object for `waitForLoading` async takeScreenshotAndUpload({ screenshotPath: screenshotPath, withMask = false, selector = false, delay = false, pageToWait = false }) { //Delay (need to have a page to wait) if (delay && pageToWait) { //add wait to avoid thumbnail error on screenshots await t.wait(delay) //relaod page to load thumbnails await t.eval(() => location.reload(true)) await checkAllImagesExists() await pageToWait.waitForLoading() } //set Mask if (withMask) { await this.setMaksCoordonnates(withMask) } else { await this.resetMask() } this.options.properties.os = await getNavigatorOs() this.options.properties.browser = await getNavigatorName() this.options.properties.resolution = await getResolution() if (selector) { await t.takeElementScreenshot(selector, `${screenshotPath}.png`) } else { await t.takeScreenshot(`${screenshotPath}.png`) } //VisualReview doesn't handle timeout, so lets add a timeout here to avoid breaking the CI Promise.race([ this.uploadScreenshot(`./reports/${screenshotPath}.png`), new Promise(function(resolve, reject) { setTimeout( () => reject( new Error(`❌ VisualReview - "${screenshotPath}.png" timeout`) ), VR_UPLOAD_DELAY ) }) ]).then( function() { console.log(`➡️ "${screenshotPath}.png" uploaded`) }, function(error) { //log error instead of throwing error so tests don't crash if VR server is taking too long console.log(error.message) } ) }
//@param { number } numOfFiles : number of file to select async selectPhotos(numOfFiles) { console.log('Selecting ' + numOfFiles + ' picture(s)') await isExistingAndVisibile(selectors.photoThumb(0), '1st Photo thumb') await t.hover(selectors.photoThumb(0)) //Only one 'hover' as all checkbox should be visible once the 1st checkbox is checked for (let i = 0; i < numOfFiles; i++) { await isExistingAndVisibile( selectors.photoThumb(i), `${i + 1}th Photo thumb` ) await t.click(selectors.photoCheckbox.nth(i)) } }
//@param {number} index: index of open file (need to know if it's first or last file) async navigateToNextFile(index) { if (index == t.ctx.totalFilesCount - 1) { //this is the last picture, so next button does not exist await t .expect(selectors.viewerNavNext.exists) .notOk('Next button on last picture') } else { await t .hover(selectors.viewerNavNext) //not last photo, so next button should exists .expect(selectors.btnViewerNavNext.visible) .ok('Next arrow does not show up') .click(selectors.btnViewerNavNext) await this.waitForLoading() } }
//@param {number} index: index of open file (need to know if it's first or last file) async navigateToPrevFile(index) { if (index == 0) { //this is the 1st picture, so previous button does not exist await t .expect(selectors.viewerNavPrevious.exists) .notOk('Previous button on first picture') } else { await t .hover(selectors.viewerNavPrevious) //not 1st photo, so previous button should exists .expect(selectors.btnViewerNavPrevious.visible) .ok('Previous arrow does not show up') .click(selectors.viewerNavPrevious) await this.waitForLoading() } }
async cloneNotebook(notebookName) { await this.selectNotebookByName(notebookName); await mouseenterTrigger('.btn-ignite:contains(Actions)'); await t.click(Selector('a').withText('Clone')); return this.createNotebookModal.confirm(); }
async createNotebook(notebookName) { await t.click(this.createNotebookButton); await this.createNotebookModal.enterValue(notebookName); return this.createNotebookModal.confirm(); }
test('Test1', async() => { await t .useRole(someUser) .expect(userName.textContent).eql('SomeUser') .useRole(Role.anonymous()) .expect(userName.textContent).eql(''); })
async waitForLoading() { await t.expect(selectors.loading.exists).notOk('Page still loading') await isExistingAndVisibile( selectors.albumContentWrapper, 'Content Wrapper' ) }
const role2 = Role('http://localhost:3000/fixtures/api/es-next/roles/pages/login-page.html', async () => { await t .typeText('input[name="name"]', 'User2') .click('input[value="LogIn"]'); role2Executions++; });
//@param { [string] } NameArray: files names to select async selectPhotosByName(NameArray) { console.log('Selecting ' + NameArray.length + ' picture(s)') await isExistingAndVisibile( selectors.photoThumbByName(NameArray[0]), `Photo thumb for ${NameArray[0]}` ) await t.hover(selectors.photoThumbByName(NameArray[0])) //Only one 'hover' as all checkbox should be visible once the 1st checkbox is checked for (let i = 0; i < NameArray.length; i++) { await isExistingAndVisibile( selectors.photoThumbByName(NameArray[i]), `Photo thumb for ${NameArray[i]}` ) await t.click(selectors.photoThumbByNameCheckbox(NameArray[i])) } }
async goToAlbums() { await isExistingAndVisibile(selectors.sidebarPhotos, 'Sidebar') await isExistingAndVisibile(selectors.btnNavToAlbum, 'Album Button') await t .click(selectors.btnNavToAlbum) .expect(getPageUrl()) .contains('albums') }
async deleteAllNotebooks() { await this.selectAllNotebooks(); await mouseenterTrigger('.btn-ignite:contains(Actions)'); await t.click(Selector('a').withText('Delete')); return confirmation.confirm(); }
test('Selector "nth()" method', async() => { // String selector const getSecondEl = Selector('.idxEl').nth(-3); let el = await getSecondEl(); await t.expect(el.id).eql('el2'); // Function selector const getThirdEl = Selector(() => document.querySelectorAll('.idxEl')).nth(2); el = await getThirdEl(); await t.expect(el.id).eql('el3'); // If single node is returned index should be always 0 const getFirstEl = Selector(() => document.querySelectorAll('.idxEl')[0]).nth(2); el = await getFirstEl(); await t.expect(el).eql(null); // Should work on parameterized selectors const elWithClass = Selector(className => document.querySelectorAll('.' + className)); await t.expect(await elWithClass('idxEl').nth(2).id).eql('el3'); await t.expect(await elWithClass('idxEl').nth(-3).id).eql('el2'); // Should be overridable await t.expect(await elWithClass('idxEl').nth(2).nth(1).id).eql('el2'); await t.expect(await getSecondEl.nth(2).id).eql('el3'); });
test('Test2', async () => { // Switch to role1 await t .useRole(role1) .expect(token.textContent).eql('') .expect(userName.textContent).eql('User1') .expect(localStorageToken.textContent).eql('123456789User1') .expect(sessionStorageToken.textContent).eql(''); // Switch to role2 await t .useRole(role2) .expect(token.textContent).eql('') .expect(userName.textContent).eql('User2') .expect(localStorageToken.textContent).eql('123456789User2') .expect(sessionStorageToken.textContent).eql(''); });
test('Test1', async () => { await t .useRole(someUser) .expect(userName.textContent).eql('SomeUser') .expect(localStorageToken.textContent).eql('123456789SomeUser') .useRole(Role.anonymous()) .expect(userName.textContent).eql('') .expect(localStorageToken.textContent).eql(''); });
async selectNotebookByName(notebookName) { const notebookRows = await Selector('.notebook-name a'); const notebookRowsIndices = _.range(await notebookRows.count + 1); const notebookRowIndex = notebookRowsIndices.findIndex(async(i) => { return notebookName === await notebookRows.nth(i).innerText; }); return t.click(Selector('.ui-grid-selection-row-header-buttons').nth(notebookRowIndex + 1).parent()); }
test('`innerText` element snapshot property', async() => { const el = await getElementById('htmlElementWithInnerText'); if (!el.innerText) throw new Error(); // NOTE: we have to use this regexp because the innerText field // returns a little bit different values in IE9 and other browsers await t.expect(/^Hey\nyo test {1,2}test( \u0000)?/.test(el.innerText.trim())).ok(); });
// @param {String} albumName : Name for the new album // @param { number } photoNumber : Number of photos to add to the new album (it will add the first X photos from the timeline) // click on new album button, check the new album page, give a name to album and select photos async addNewAlbum(albumName, photoNumber) { await this.waitForLoading() await isExistingAndVisibile( selectors.toolbarAlbumsList, 'toolbar (album list)' ) await isExistingAndVisibile(selectors.btnNewAlbum, 'New album button') await t.click(selectors.btnNewAlbum) //Check new album page : await t.expect(getPageUrl()).contains('albums/new') await isExistingAndVisibile(selectors.inputAlbumName, 'Input album Name') await t .expect(selectors.inputAlbumName.value) .eql('Untitled album') .expect(selectors.inputAlbumName.focused) .ok('Input album Name is not focus') const allPhotosAlbumCount = await albumPage.getPhotosToAddCount( 'On create Album page' ) await t.expect(allPhotosAlbumCount).eql(t.ctx.totalFilesCount) //all photos are displayed await isExistingAndVisibile( selectors.btnValidateAlbum, 'Create Album Button' ) await t.typeText(selectors.inputAlbumName, albumName) await albumPage.selectPhotostoAdd(0, photoNumber) await t.click(selectors.btnValidateAlbum) }
test('Test1', async () => { // Check initial state await t .expect(userName.textContent).eql('') .expect(token.textContent).eql('') .expect(localStorageToken.textContent).eql('') .expect(sessionStorageToken.textContent).eql(''); // Switch to role1 await t .useRole(role1) .expect(token.textContent).eql('') .expect(userName.textContent).eql('User1') .expect(localStorageToken.textContent).eql('123456789User1') .expect(sessionStorageToken.textContent).eql(''); // Set token for role1 await setToken('Token1'); await t .expect(token.textContent).eql('Token1') .expect(sessionStorageToken.textContent).eql('qwertyUser1'); // Switch to role2 await t .useRole(role2) .expect(token.textContent).eql('') .expect(userName.textContent).eql('User2') .expect(localStorageToken.textContent).eql('123456789User2') .expect(sessionStorageToken.textContent).eql(''); // Set token for role2 await setToken('Token2'); await t.expect(token.textContent).eql('Token2') .expect(sessionStorageToken.textContent).eql('qwertyUser2'); // Switch to role1 await t .useRole(role1) .expect(token.textContent).eql('Token1') .expect(userName.textContent).eql('User1') .expect(localStorageToken.textContent).eql('123456789User1') .expect(sessionStorageToken.textContent).eql('qwertyUser1'); // Switch to role2 await t .useRole(role2) .expect(token.textContent).eql('Token2') .expect(userName.textContent).eql('User2') .expect(localStorageToken.textContent).eql('123456789User2') .expect(sessionStorageToken.textContent).eql('qwertyUser2'); });
test('Selector "sibling" method', async() => { // Index filter await t.expect(await Selector('#el2').sibling(1).id).eql('el3'); await t.expect(await Selector('#el2').sibling().sibling().id).eql('el2'); await t.expect(await Selector('#el1').sibling(2).id).eql('el4'); await t.expect(await Selector('#el1').sibling(-3).id).eql('el2'); await t.expect(await Selector('#el2').sibling(0).count).eql(1); // CSS selector filter await t.expect(await Selector('#selectInput').sibling('[type=checkbox]').id).eql('checkInput'); // Function selector await t.expect(await Selector('#el2').sibling(el => el.id === 'el3').id).eql('el3'); // Parameterized selector const withId = Selector(id => document.getElementById(id)); await t.expect(await withId('el2').sibling().id).eql('el1'); // With filters await t.expect(await Selector('#el2').sibling().withText('element 4').id).eql('el4'); });
test('Snapshot `hasClass` method', async() => { let el = await getElementById('htmlElement'); await t.expect(el.hasClass('yo')).ok(); await t.expect(el.hasClass('cool')).ok(); await t.expect(el.hasClass('42')).notOk(); el = await getElementById('svgElement'); await t.expect(el.hasClass('svg1')).ok(); await t.expect(el.hasClass('svg2')).ok(); await t.expect(el.hasClass('cool')).notOk(); });
const selectOptionInExpandingList = async () => { await t .click(expandingSelect) .click(expandingSelect.find('option').nth(1)) .expect(expandingSelect.value).eql('Two'); };
test('Click on select option (IE)', async () => { await selectOptionInExpandingList(); await t.expect(getEvents()).eql(0); await selectOptionInScrollingList(); await t.expect(getEvents()).eql(0); });
const selectOptionInScrollingList = async () => { await t .click(scrollingSelect) .click(scrollingSelect.find('option').nth(2)) .expect(scrollingSelect.value).eql('Tres'); };
async close() { await t.click('.modal .close'); }