From 22ec058431e07de625e0687e65e801aa81f68c6d Mon Sep 17 00:00:00 2001 From: Ryan Cohen Date: Mon, 15 Aug 2022 08:34:38 +0900 Subject: [PATCH] test: add cypress foundation (#2903) [skip ci] --- .dockerignore | 1 + .github/workflows/cypress.yml | 30 ++ .gitignore | 5 + cypress.config.ts | 15 + cypress/config/settings.cypress.json | 149 ++++++++++ cypress/e2e/discover.cy.ts | 44 +++ cypress/e2e/login.cy.ts | 13 + cypress/e2e/movie-details.cy.ts | 12 + cypress/e2e/tv-details.cy.ts | 12 + cypress/e2e/user/user-list.cy.ts | 67 +++++ cypress/support/commands.ts | 26 ++ cypress/support/e2e.ts | 7 + cypress/support/index.ts | 12 + cypress/tsconfig.json | 10 + package.json | 6 +- server/scripts/prepareTestDb.ts | 53 ++++ src/components/Common/Header/index.tsx | 5 +- src/components/Common/Modal/index.tsx | 4 + src/components/Layout/Sidebar/index.tsx | 4 + src/components/Layout/index.tsx | 1 + src/components/Login/LocalLogin.tsx | 3 + src/components/MovieDetails/index.tsx | 2 +- src/components/Slider/index.tsx | 2 +- src/components/TitleCard/index.tsx | 6 +- src/components/TvDetails/index.tsx | 2 +- src/components/UserList/index.tsx | 2 +- yarn.lock | 372 +++++++++++++++++++++++- 27 files changed, 848 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/cypress.yml create mode 100644 cypress.config.ts create mode 100644 cypress/config/settings.cypress.json create mode 100644 cypress/e2e/discover.cy.ts create mode 100644 cypress/e2e/login.cy.ts create mode 100644 cypress/e2e/movie-details.cy.ts create mode 100644 cypress/e2e/tv-details.cy.ts create mode 100644 cypress/e2e/user/user-list.cy.ts create mode 100644 cypress/support/commands.ts create mode 100644 cypress/support/e2e.ts create mode 100644 cypress/support/index.ts create mode 100644 cypress/tsconfig.json create mode 100644 server/scripts/prepareTestDb.ts diff --git a/.dockerignore b/.dockerignore index 7d669c86..21a5da86 100644 --- a/.dockerignore +++ b/.dockerignore @@ -26,3 +26,4 @@ public/os_logo_filled.png public/preview.jpg snap stylelint.config.js +cypress diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml new file mode 100644 index 00000000..8a0ac34f --- /dev/null +++ b/.github/workflows/cypress.yml @@ -0,0 +1,30 @@ +name: Cypress Tests + +on: + pull_request: + branches: + - '*' + push: + branches: + - develop + +jobs: + cypress-run: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Cypress run + uses: cypress-io/github-action@v4 + with: + build: yarn cypress:build + start: yarn start + wait-on: 'http://localhost:5055' + record: true + env: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WITH_MIGRATIONS: true + # Fix test titles in cypress dashboard + COMMIT_INFO_MESSAGE: ${{github.event.pull_request.title}} + COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha}} diff --git a/.gitignore b/.gitignore index 7d606105..1509c597 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,8 @@ config/db/db.sqlite3-journal # VS Code .vscode/launch.json + +# Cypress +cypress.env.json +cypress/videos +cypress/screenshots diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 00000000..1c454730 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'cypress'; + +export default defineConfig({ + projectId: 'onnqy3', + e2e: { + baseUrl: 'http://localhost:5055', + experimentalSessionAndOrigin: true, + }, + env: { + ADMIN_EMAIL: 'admin@seerr.dev', + ADMIN_PASSWORD: 'test1234', + USER_EMAIL: 'friend@seerr.dev', + USER_PASSWORD: 'test1234', + }, +}); diff --git a/cypress/config/settings.cypress.json b/cypress/config/settings.cypress.json new file mode 100644 index 00000000..bb7b661b --- /dev/null +++ b/cypress/config/settings.cypress.json @@ -0,0 +1,149 @@ +{ + "clientId": "6919275e-142a-48d8-be6b-93594cbd4626", + "vapidPrivate": "tmnslaO8ZWN6bNbSEv_rolPeBTlNxOwCCAHrM9oZz3M", + "vapidPublic": "BK_EpP8NDm9waor2zn6_S28o3ZYv4kCkJOfYpO3pt3W6jnPmxrgTLANUBNbbyaNatPnSQ12De9CeqSYQrqWzHTs", + "main": { + "apiKey": "testkey", + "applicationTitle": "Overseerr", + "applicationUrl": "", + "csrfProtection": false, + "cacheImages": false, + "defaultPermissions": 32, + "defaultQuotas": { + "movie": {}, + "tv": {} + }, + "hideAvailable": false, + "localLogin": true, + "newPlexLogin": true, + "region": "", + "originalLanguage": "", + "trustProxy": false, + "partialRequestsEnabled": true, + "locale": "en" + }, + "plex": { + "name": "Seerr", + "ip": "192.168.1.1", + "port": 32400, + "useSsl": false, + "libraries": [ + { + "id": "1", + "name": "Movies", + "enabled": true, + "type": "movie" + } + ], + "machineId": "test" + }, + "tautulli": {}, + "radarr": [], + "sonarr": [], + "public": { + "initialized": true + }, + "notifications": { + "agents": { + "email": { + "enabled": false, + "options": { + "emailFrom": "", + "smtpHost": "", + "smtpPort": 587, + "secure": false, + "ignoreTls": false, + "requireTls": false, + "allowSelfSigned": false, + "senderName": "Overseerr" + } + }, + "discord": { + "enabled": false, + "types": 0, + "options": { + "webhookUrl": "", + "enableMentions": true + } + }, + "lunasea": { + "enabled": false, + "types": 0, + "options": { + "webhookUrl": "" + } + }, + "slack": { + "enabled": false, + "types": 0, + "options": { + "webhookUrl": "" + } + }, + "telegram": { + "enabled": false, + "types": 0, + "options": { + "botAPI": "", + "chatId": "", + "sendSilently": false + } + }, + "pushbullet": { + "enabled": false, + "types": 0, + "options": { + "accessToken": "" + } + }, + "pushover": { + "enabled": false, + "types": 0, + "options": { + "accessToken": "", + "userToken": "" + } + }, + "webhook": { + "enabled": false, + "types": 0, + "options": { + "webhookUrl": "", + "jsonPayload": "IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i" + } + }, + "webpush": { + "enabled": false, + "options": {} + }, + "gotify": { + "enabled": false, + "types": 0, + "options": { + "url": "", + "token": "" + } + } + } + }, + "jobs": { + "plex-recently-added-scan": { + "schedule": "0 */5 * * * *" + }, + "plex-full-scan": { + "schedule": "0 0 3 * * *" + }, + "radarr-scan": { + "schedule": "0 0 4 * * *" + }, + "sonarr-scan": { + "schedule": "0 30 4 * * *" + }, + "download-sync": { + "schedule": "0 * * * * *" + }, + "download-sync-reset": { + "schedule": "0 0 1 * * *" + } + } + } diff --git a/cypress/e2e/discover.cy.ts b/cypress/e2e/discover.cy.ts new file mode 100644 index 00000000..c08615f5 --- /dev/null +++ b/cypress/e2e/discover.cy.ts @@ -0,0 +1,44 @@ +const clickFirstTitleCardInSlider = (sliderTitle: string): void => { + cy.contains('.slider-header', sliderTitle) + .next('[data-testid=media-slider]') + .find('[data-testid=title-card]') + .first() + .trigger('mouseover') + .find('[data-testid=title-card-title]') + .invoke('text') + .then((text) => { + cy.contains('.slider-header', sliderTitle) + .next('[data-testid=media-slider]') + .find('[data-testid=title-card]') + .first() + .click(); + cy.get('[data-testid=media-title]').should('contain', text); + }); +}; + +describe('Discover', () => { + beforeEach(() => { + cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD')); + cy.visit('/'); + }); + + it('loads a trending item', () => { + clickFirstTitleCardInSlider('Trending'); + }); + + it('loads popular movies', () => { + clickFirstTitleCardInSlider('Popular Movies'); + }); + + it('loads upcoming movies', () => { + clickFirstTitleCardInSlider('Upcoming Movies'); + }); + + it('loads popular series', () => { + clickFirstTitleCardInSlider('Popular Series'); + }); + + it('loads upcoming series', () => { + clickFirstTitleCardInSlider('Upcoming Series'); + }); +}); diff --git a/cypress/e2e/login.cy.ts b/cypress/e2e/login.cy.ts new file mode 100644 index 00000000..7aba583b --- /dev/null +++ b/cypress/e2e/login.cy.ts @@ -0,0 +1,13 @@ +describe('Login Page', () => { + it('succesfully logs in as an admin', () => { + cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD')); + cy.visit('/'); + cy.contains('Recently Added'); + }); + + it('succesfully logs in as a local user', () => { + cy.login(Cypress.env('USER_EMAIL'), Cypress.env('USER_PASSWORD')); + cy.visit('/'); + cy.contains('Recently Added'); + }); +}); diff --git a/cypress/e2e/movie-details.cy.ts b/cypress/e2e/movie-details.cy.ts new file mode 100644 index 00000000..c68e052f --- /dev/null +++ b/cypress/e2e/movie-details.cy.ts @@ -0,0 +1,12 @@ +describe('Movie Details', () => { + it('loads a movie page', () => { + cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD')); + // Try to load minions: rise of gru + cy.visit('/movie/438148'); + + cy.get('[data-testid=media-title]').should( + 'contain', + 'Minions: The Rise of Gru (2022)' + ); + }); +}); diff --git a/cypress/e2e/tv-details.cy.ts b/cypress/e2e/tv-details.cy.ts new file mode 100644 index 00000000..3cb2f8cf --- /dev/null +++ b/cypress/e2e/tv-details.cy.ts @@ -0,0 +1,12 @@ +describe('TV Details', () => { + it('loads a movie page', () => { + cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD')); + // Try to load stranger things + cy.visit('/tv/66732'); + + cy.get('[data-testid=media-title]').should( + 'contain', + 'Stranger Things (2016)' + ); + }); +}); diff --git a/cypress/e2e/user/user-list.cy.ts b/cypress/e2e/user/user-list.cy.ts new file mode 100644 index 00000000..4e8cf4bd --- /dev/null +++ b/cypress/e2e/user/user-list.cy.ts @@ -0,0 +1,67 @@ +const testUser = { + displayName: 'Test User', + emailAddress: 'test@seeerr.dev', + password: 'test1234', +}; + +describe('User List', () => { + beforeEach(() => { + cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD')); + }); + + it('opens the user list from the home page', () => { + cy.visit('/'); + + cy.get('[data-testid=sidebar-toggle]').click(); + cy.get('[data-testid=sidebar-menu-users-mobile]').click(); + + cy.get('[data-testid=page-header').should('contain', 'User List'); + }); + + it('can find the admin user and friend user in the user list', () => { + cy.visit('/users'); + + cy.get('[data-testid=user-list-row]').contains(Cypress.env('ADMIN_EMAIL')); + cy.get('[data-testid=user-list-row]').contains(Cypress.env('USER_EMAIL')); + }); + + it('can create a local user', () => { + cy.visit('/users'); + + cy.contains('Create Local User').click(); + + cy.get('[data-testid=modal-title').should('contain', 'Create Local User'); + + cy.get('#displayName').type(testUser.displayName); + cy.get('#email').type(testUser.emailAddress); + cy.get('#password').type(testUser.password); + + cy.intercept('/api/v1/user?take=10&skip=0&sort=displayname').as('user'); + + cy.get('[data-testid=modal-ok-button').click(); + + cy.wait('@user'); + + cy.get('[data-testid=user-list-row]').contains(testUser.emailAddress); + }); + + it('can delete the created local test user', () => { + cy.visit('/users'); + + cy.contains('[data-testid=user-list-row]', testUser.emailAddress) + .contains('Delete') + .click(); + + cy.get('[data-testid=modal-title]').should('contain', 'Delete User'); + + cy.intercept('/api/v1/user?take=10&skip=0&sort=displayname').as('user'); + + cy.get('[data-testid=modal-ok-button').should('contain', 'Delete').click(); + + cy.wait('@user'); + + cy.get('[data-testid=user-list-row]') + .contains(testUser.emailAddress) + .should('not.exist'); + }); +}); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts new file mode 100644 index 00000000..a4c3cfcd --- /dev/null +++ b/cypress/support/commands.ts @@ -0,0 +1,26 @@ +/// + +Cypress.Commands.add('login', (email, password) => { + cy.session( + [email, password], + () => { + cy.visit('/login'); + cy.contains('Use your Overseerr account').click(); + + cy.get('[data-testid=email]').type(email); + cy.get('[data-testid=password]').type(password); + + cy.intercept('/api/v1/auth/local').as('localLogin'); + cy.get('[data-testid=local-signin-button]').click(); + + cy.wait('@localLogin'); + + cy.url().should('contain', '/'); + }, + { + validate() { + cy.request('/api/v1/auth/me').its('status').should('eq', 200); + }, + } + ); +}); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 00000000..7a7697ca --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1,7 @@ +import './commands'; + +before(() => { + if (Cypress.env('SEED_DATABASE')) { + cy.exec('yarn cypress:prepare'); + } +}); diff --git a/cypress/support/index.ts b/cypress/support/index.ts new file mode 100644 index 00000000..72eb11bd --- /dev/null +++ b/cypress/support/index.ts @@ -0,0 +1,12 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +/// + +declare global { + namespace Cypress { + interface Chainable { + login(email?: string, password?: string): Chainable; + } + } +} + +export {}; diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json new file mode 100644 index 00000000..1b6425b8 --- /dev/null +++ b/cypress/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["es5", "dom"], + "types": ["cypress", "node"], + "resolveJsonModule": true, + "esModuleInterop": true + }, + "include": ["**/*.ts"] +} diff --git a/package.json b/package.json index adbc0399..1f3b226f 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "migration:run": "ts-node --project server/tsconfig.json ./node_modules/typeorm/cli.js migration:run", "format": "prettier --loglevel warn --write --cache .", "format:check": "prettier --check --cache .", - "prepare": "husky install" + "prepare": "husky install", + "cypress:open": "cypress open", + "cypress:prepare": "ts-node --files server/scripts/prepareTestDb.ts", + "cypress:build": "yarn build && yarn cypress:prepare" }, "repository": { "type": "git", @@ -121,6 +124,7 @@ "babel-plugin-react-intl-auto": "^3.3.0", "commitizen": "^4.2.4", "copyfiles": "^2.4.1", + "cypress": "^10.4.0", "cz-conventional-changelog": "^3.3.0", "eslint": "^8.21.0", "eslint-config-next": "^12.2.3", diff --git a/server/scripts/prepareTestDb.ts b/server/scripts/prepareTestDb.ts new file mode 100644 index 00000000..d38e37d7 --- /dev/null +++ b/server/scripts/prepareTestDb.ts @@ -0,0 +1,53 @@ +import { createConnection, getRepository } from 'typeorm'; +import { copyFileSync } from 'fs'; +import { UserType } from '../constants/user'; +import { User } from '../entity/User'; +import path from 'path'; + +const prepareDb = async () => { + // Copy over test settings.json + copyFileSync( + path.join(__dirname, '../../cypress/config/settings.cypress.json'), + path.join(__dirname, '../../config/settings.json') + ); + + // Connect to DB and seed test data + const dbConnection = await createConnection(); + + await dbConnection.dropDatabase(); + + // Run migrations in production + if (process.env.WITH_MIGRATIONS === 'true') { + await dbConnection.runMigrations(); + } else { + await dbConnection.synchronize(); + } + + const userRepository = getRepository(User); + + // Create the admin user + const user = new User(); + user.plexId = 1; + user.plexToken = '1234'; + user.plexUsername = 'admin'; + user.username = 'admin'; + user.email = 'admin@seerr.dev'; + user.userType = UserType.PLEX; + await user.setPassword('test1234'); + user.permissions = 2; + user.avatar = 'https://plex.tv/assets/images/avatar/default.png'; + await userRepository.save(user); + + // Create the other user + const otherUser = new User(); + otherUser.plexId = 1; + otherUser.username = 'friend'; + otherUser.email = 'friend@seerr.dev'; + otherUser.userType = UserType.LOCAL; + await otherUser.setPassword('test1234'); + otherUser.permissions = 32; + otherUser.avatar = 'https://plex.tv/assets/images/avatar/default.png'; + await userRepository.save(otherUser); +}; + +prepareDb(); diff --git a/src/components/Common/Header/index.tsx b/src/components/Common/Header/index.tsx index b7c88ddd..aa81e45e 100644 --- a/src/components/Common/Header/index.tsx +++ b/src/components/Common/Header/index.tsx @@ -13,7 +13,10 @@ const Header: React.FC = ({ return (
-

+

{children} diff --git a/src/components/Common/Modal/index.tsx b/src/components/Common/Modal/index.tsx index 083a5fd7..777128c0 100644 --- a/src/components/Common/Modal/index.tsx +++ b/src/components/Common/Modal/index.tsx @@ -141,6 +141,7 @@ const Modal: React.FC = ({ {title} @@ -160,6 +161,7 @@ const Modal: React.FC = ({ onClick={onOk} className="ml-3" disabled={okDisabled} + data-testid="modal-ok-button" > {okText ? okText : 'Ok'} @@ -170,6 +172,7 @@ const Modal: React.FC = ({ onClick={onSecondary} className="ml-3" disabled={secondaryDisabled} + data-testid="modal-secondary-button" > {secondaryText} @@ -189,6 +192,7 @@ const Modal: React.FC = ({ buttonType={cancelButtonType} onClick={onCancel} className="ml-3 sm:ml-0" + data-testid="modal-cancel-button" > {cancelText ? cancelText diff --git a/src/components/Layout/Sidebar/index.tsx b/src/components/Layout/Sidebar/index.tsx index 5530d954..6c5daae2 100644 --- a/src/components/Layout/Sidebar/index.tsx +++ b/src/components/Layout/Sidebar/index.tsx @@ -37,6 +37,7 @@ interface SidebarLinkProps { as?: string; requiredPermission?: Permission | Permission[]; permissionType?: 'and' | 'or'; + dataTestId?: string; } const SidebarLinks: SidebarLinkProps[] = [ @@ -72,6 +73,7 @@ const SidebarLinks: SidebarLinkProps[] = [ svgIcon: , activeRegExp: /^\/users/, requiredPermission: Permission.MANAGE_USERS, + dataTestId: 'sidebar-menu-users', }, { href: '/settings', @@ -168,6 +170,7 @@ const Sidebar: React.FC = ({ open, setClosed }) => { : 'hover:bg-gray-700 focus:bg-gray-700' } `} + data-testid={`${sidebarLink.dataTestId}-mobile`} > {sidebarLink.svgIcon} {intl.formatMessage( @@ -229,6 +232,7 @@ const Sidebar: React.FC = ({ open, setClosed }) => { : 'hover:bg-gray-700 focus:bg-gray-700' } `} + data-testid={sidebarLink.dataTestId} > {sidebarLink.svgIcon} {intl.formatMessage(messages[sidebarLink.messagesKey])} diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 5b57df97..41ba1553 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -68,6 +68,7 @@ const Layout: React.FC = ({ children }) => { } transition duration-300 focus:outline-none lg:hidden`} aria-label="Open sidebar" onClick={() => setSidebarOpen(true)} + data-testid="sidebar-toggle" > diff --git a/src/components/Login/LocalLogin.tsx b/src/components/Login/LocalLogin.tsx index 2480a8d5..8ab772db 100644 --- a/src/components/Login/LocalLogin.tsx +++ b/src/components/Login/LocalLogin.tsx @@ -77,6 +77,7 @@ const LocalLogin: React.FC = ({ revalidate }) => { name="email" type="text" inputMode="email" + data-testid="email" />

{errors.email && touched.email && ( @@ -94,6 +95,7 @@ const LocalLogin: React.FC = ({ revalidate }) => { name="password" type="password" autoComplete="current-password" + data-testid="password" />
{errors.password && touched.password && ( @@ -113,6 +115,7 @@ const LocalLogin: React.FC = ({ revalidate }) => { buttonType="primary" type="submit" disabled={isSubmitting || !isValid} + data-testid="local-signin-button" > diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index edb4d8bd..fc211807 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -340,7 +340,7 @@ const MovieDetails: React.FC = ({ movie }) => { /> )} -

+

{data.title}{' '} {data.releaseDate && ( diff --git a/src/components/Slider/index.tsx b/src/components/Slider/index.tsx index a2498323..45d43f7a 100644 --- a/src/components/Slider/index.tsx +++ b/src/components/Slider/index.tsx @@ -149,7 +149,7 @@ const Slider: React.FC = ({ }; return ( -
+

diff --git a/src/components/TvDetails/index.tsx b/src/components/TvDetails/index.tsx index 50558892..f94c183b 100644 --- a/src/components/TvDetails/index.tsx +++ b/src/components/TvDetails/index.tsx @@ -343,7 +343,7 @@ const TvDetails: React.FC = ({ tv }) => { /> )} -

+

{data.name}{' '} {data.firstAirDate && ( diff --git a/src/components/UserList/index.tsx b/src/components/UserList/index.tsx index a0330c0c..1a3f7894 100644 --- a/src/components/UserList/index.tsx +++ b/src/components/UserList/index.tsx @@ -557,7 +557,7 @@ const UserList: React.FC = () => { {data?.results.map((user) => ( - + {isUserPermsEditable(user.id) && ( = 2.1.2 < 3.0.0" -ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6643,6 +6880,13 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-ci@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + is-cidr@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814" @@ -6718,7 +6962,7 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-installed-globally@^0.4.0: +is-installed-globally@^0.4.0, is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== @@ -6852,6 +7096,11 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-utf8@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -7066,6 +7315,16 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + jstransformer@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" @@ -7169,6 +7428,11 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -7357,6 +7621,20 @@ lint-staged@^12.3.5: supports-color "^9.2.1" yaml "^1.10.2" +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.1" + through "^2.3.8" + wrap-ansi "^7.0.0" + listr2@^4.0.1: version "4.0.5" resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" @@ -7483,6 +7761,11 @@ lodash.mergewith@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== +lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -7508,6 +7791,14 @@ lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.1 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + log-update@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" @@ -8679,7 +8970,7 @@ npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1: npm-package-arg "^9.0.0" proc-log "^2.0.0" -npm-run-path@^4.0.1: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -8989,6 +9280,11 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -9234,6 +9530,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -9249,7 +9550,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.3.0: +pify@^2.2.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== @@ -9414,6 +9715,11 @@ prettier@^2.7.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +pretty-bytes@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + preview-email@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/preview-email/-/preview-email-3.0.5.tgz#09c32ba43c450ead16b309d9e5cb10f90ff45a95" @@ -9501,6 +9807,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + psl@^1.1.28: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -10109,6 +10420,13 @@ remark-rehype@^10.0.0: mdast-util-to-hast "^12.1.0" unified "^10.0.0" +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== + dependencies: + throttleit "^1.0.0" + request-promise-core@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346" @@ -10304,6 +10622,13 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" +rxjs@^7.5.1: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + rxjs@^7.5.5: version "7.5.5" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" @@ -10741,7 +11066,7 @@ sqlite3@^5.0.2: optionalDependencies: node-gyp "3.x" -sshpk@^1.7.0: +sshpk@^1.14.1, sshpk@^1.7.0: version "1.17.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== @@ -11011,6 +11336,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^9.2.1: version "9.2.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" @@ -11162,6 +11494,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== + through2@^2.0.1, through2@~2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -11214,6 +11551,13 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -12133,6 +12477,14 @@ yargs@^17.0.0, yargs@^17.0.1: y18n "^5.0.5" yargs-parser "^21.0.0" +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"