diff --git a/package-lock.json b/package-lock.json index 566f89c7e..43ec99d9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1986,9 +1986,9 @@ "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", - "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", @@ -2153,9 +2153,9 @@ "dev": true }, "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", "dev": true, "optional": true, "requires": { @@ -2456,9 +2456,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -4990,9 +4990,9 @@ } }, "chromedriver": { - "version": "91.0.1", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-91.0.1.tgz", - "integrity": "sha512-9LktpHiUxM4UWUsr+jI1K1YKx2GENt6BKKJ2mibPj1Wc6ODzX/3fFIlr8CZ4Ftuyga+dHTTbAyPWKwKvybEbKA==", + "version": "92.0.1", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-92.0.1.tgz", + "integrity": "sha512-LptlDVCs1GgyFNVbRoHzzy948JDVzTgGiVPXjNj385qXKQP3hjAVBIgyvb/Hco0xSEW8fjwJfsm1eQRmu6t4pQ==", "dev": true, "requires": { "@testim/chrome-version": "^1.0.7", @@ -6626,9 +6626,9 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, "ignore": { @@ -8025,9 +8025,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -8064,17 +8064,16 @@ "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "dependencies": { "braces": { @@ -8133,16 +8132,14 @@ "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" - }, - "dependencies": { - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - } } }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8258,9 +8255,9 @@ "dev": true }, "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", + "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -8868,9 +8865,9 @@ } }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz", + "integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==", "dev": true }, "font-atlas": { @@ -11077,9 +11074,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" diff --git a/package.json b/package.json index 3169468f2..346100a32 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "babel-preset-es2015": "6.22.0", "babel-preset-react": "6.22.0", "bowser": "1.9.4", - "chromedriver": "91.0.1", + "chromedriver": "92.0.1", "classnames": "2.2.5", "cookie": "0.4.1", "copy-webpack-plugin": "4.6.0", diff --git a/test/integration/footer-links.test.js b/test/integration/footer-links.test.js index 1e2eadd2f..d6b39af3f 100644 --- a/test/integration/footer-links.test.js +++ b/test/integration/footer-links.test.js @@ -1,3 +1,5 @@ +// these tests do not sign in as a user + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/homepage-rows.test.js b/test/integration/homepage-rows.test.js index a49f6b558..84bf8fc52 100644 --- a/test/integration/homepage-rows.test.js +++ b/test/integration/homepage-rows.test.js @@ -1,3 +1,5 @@ +// these tests do not sign in as a user + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/join.test.js b/test/integration/join.test.js index c8cd95ea8..a08e6861d 100644 --- a/test/integration/join.test.js +++ b/test/integration/join.test.js @@ -1,3 +1,5 @@ +// these tests do not sign in as a user + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/my-stuff.test.js b/test/integration/my-stuff.test.js index 5a409840f..1bc650dd1 100644 --- a/test/integration/my-stuff.test.js +++ b/test/integration/my-stuff.test.js @@ -1,3 +1,5 @@ +// These tests sign in as user #1 + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/navbar.test.js b/test/integration/navbar.test.js index c26e403c8..59446de52 100644 --- a/test/integration/navbar.test.js +++ b/test/integration/navbar.test.js @@ -1,3 +1,5 @@ +// These tests do not sign in as a user + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/project-page.test.js b/test/integration/project-page.test.js index 35112fa7f..ba70d9631 100644 --- a/test/integration/project-page.test.js +++ b/test/integration/project-page.test.js @@ -1,3 +1,5 @@ +// These tests do not sign in with a user + const SeleniumHelper = require('./selenium-helpers.js'); const { @@ -35,7 +37,7 @@ describe('www-integration project-page signed out', () => { afterAll(async () => await driver.quit()); // LOGGED OUT TESTS - + test('Find fullscreen button', async () => { await clickXpath('//div[starts-with(@class, "stage_green-flag-overlay")]'); await clickXpath('//img[contains(@alt, "Enter full screen mode")]'); diff --git a/test/integration/selenium-helpers.js b/test/integration/selenium-helpers.js index 5b7fe163d..fe680daf1 100644 --- a/test/integration/selenium-helpers.js +++ b/test/integration/selenium-helpers.js @@ -29,6 +29,7 @@ class SeleniumHelper { 'getDriver', 'getLogs', 'getSauceDriver', + 'signIn', 'urlMatches', 'waitUntilGone' ]); @@ -148,6 +149,18 @@ class SeleniumHelper { }); } + // must be used on a www page + async signIn (username, password, driver) { + await this.clickXpath('//li[@class="link right login-item"]/a'); + let name = await this.findByXpath('//input[@id="frc-username-1088"]'); + await name.sendKeys(username); + let word = await this.findByXpath('//input[@id="frc-password-1088"]'); + await word.sendKeys(password); + await driver.sleep(500); + await this.clickXpath('//button[contains(@class, "button") and ' + + 'contains(@class, "submit-button") and contains(@class, "white")]'); + } + urlMatches (regex) { return this.driver.wait(until.urlMatches(regex), 1000 * 5); } diff --git a/test/integration/sign-in-and-out.test.js b/test/integration/sign-in-and-out.test.js index d015ab79c..c2c93027f 100644 --- a/test/integration/sign-in-and-out.test.js +++ b/test/integration/sign-in-and-out.test.js @@ -1,3 +1,5 @@ +// These tests sign in with user #0 (no number for the username) + const SeleniumHelper = require('./selenium-helpers.js'); const { diff --git a/test/integration/studios-page.test.js b/test/integration/studios-page.test.js index e5da61d1f..6e3ff8ad7 100644 --- a/test/integration/studios-page.test.js +++ b/test/integration/studios-page.test.js @@ -1,17 +1,33 @@ +// These tests sign in with user #2 and user #3 + import SeleniumHelper from './selenium-helpers.js'; const { findByXpath, - buildDriver + buildDriver, + clickXpath, + clickText, + signIn } = new SeleniumHelper(); let remote = process.env.SMOKE_REMOTE || false; let rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; let studioId = process.env.TEST_STUDIO_ID || 10004360; let studioUrl = rootUrl + '/studios/' + studioId; +let myStuffURL = rootUrl + '/mystuff'; +let rateLimitCheck = process.env.RATE_LIMIT_CHECK || rootUrl; + +// since the usernames end in 2 and 3 we're using username2 and username3 +// username 1 is used in other tests. Hopefully this is not confusing. +let username2 = process.env.SMOKE_USERNAME + '2'; +let username3 = process.env.SMOKE_USERNAME + '3'; +let password = process.env.SMOKE_PASSWORD; + +let promoteStudioURL; +let curatorTab; if (remote){ - jest.setTimeout(60000); + jest.setTimeout(70000); } else { jest.setTimeout(20000); } @@ -52,5 +68,83 @@ describe('studio page while signed out', () => { let descriptionText = await studioDescription.getText(); await expect(descriptionText).toEqual('a description'); }); - +}); + +describe('studio management', () => { + // These tests all start on the curators tab of a studio and signed out + + beforeAll(async () => { + driver = await buildDriver('www-integration studio management'); + await driver.get(rootUrl); + + // create a studio for tests + await signIn(username2, password, driver); + await findByXpath('//span[contains(@class, "profile-name")]'); + await driver.get(rateLimitCheck); + await driver.get(myStuffURL); + await clickXpath('//form[@id="new_studio"]/button[@type="submit"]'); + await findByXpath('//div[@class="studio-tabs"]'); + promoteStudioURL = await driver.getCurrentUrl(); + curatorTab = promoteStudioURL + 'curators'; + }); + + beforeEach(async () => { + await clickXpath('//a[contains(@class, "user-info")]'); + await clickText('Sign out'); + await driver.get(curatorTab); + await findByXpath('//div[@class="studio-tabs"]'); + }); + + afterAll(async () => await driver.quit()); + + test('invite a curator', async () => { + // sign in as user2 + await signIn(username2, password, driver); + await findByXpath('//span[contains(@class, "profile-name")]'); + + // invite user3 to curate + let inviteBox = await findByXpath('//div[@class="studio-adder-row"]/input'); + await inviteBox.sendKeys(username3); + await clickXpath('//div[@class="studio-adder-row"]/button'); + let inviteAlert = await findByXpath('//div[@class="alert-msg"]'); // the confirm alert + let alertText = await inviteAlert.getText(); + let successText = `Curator invite sent to "${username3}"`; + await expect(alertText).toMatch(successText); + }); + + test('accept curator invite', async () => { + // Sign in user3 + await signIn(username3, password, driver); + await findByXpath('//span[contains(@class, "profile-name")]'); + + // accept the curator invite + await clickXpath('//button[@class="studio-invitation-button button"]'); + let acceptSuccess = await findByXpath('//div[contains(@class,"studio-info-box-success")]'); + let acceptSuccessVisible = await acceptSuccess.isDisplayed(); + await expect(acceptSuccessVisible).toBe(true); + }); + + test('promote to manager', async () => { + // sign in as user2 + await signIn(username2, password, driver); + await findByXpath('//span[contains(@class, "profile-name")]'); + // for some reason the user isn't showing up without reloading the page + await driver.get(curatorTab); + + // promote user3 + let user3href = '/users/' + username3; + // click kebab menu on the user tile + let kebabMenuXpath = `//a[@href = "${user3href}"]/` + + 'following-sibling::div[@class="overflow-menu-container"]'; + await clickXpath(kebabMenuXpath + '/button[@class="overflow-menu-trigger"]'); + // click promote + // await clickXpath('//button[@class="promote-menu-button"]'); //<-- I think this will do it + await clickXpath(kebabMenuXpath + '/ul/li/button/span[contains(text(), "Promote")]/..'); + await findByXpath('//div[@class="promote-content"]'); + // await clickXpath(//button[contains(@class="promote-button")]) <-- add this selector to the button + await clickXpath('//div[@class="promote-button-row"]/button/span[contains(text(),"Promote")]/..'); + let promoteSuccess = await findByXpath('//div[contains(@class, "alert-success")]'); + let promoteSuccessVisible = await promoteSuccess.isDisplayed(); + await expect(promoteSuccessVisible).toBe(true); + }); });