diff --git a/.drone-docker.yml b/.drone-docker.yml index b8a1747..728c7a1 100644 --- a/.drone-docker.yml +++ b/.drone-docker.yml @@ -8,76 +8,112 @@ concurrency: trigger: event: - push - branch: - - master - - main - - development steps: -- name: replace hosts and user variables - image: ubuntu:impish - environment: - DEPLOY_HOSTNAME: - from_secret: deploy_hostname - SPT_ITEMS_HOSTNAME: - from_secret: spt_items_hostname - DEPLOY_USER: - from_secret: deploy_username - DEPLOY_SSH_KEY_PASSPHRASE: - from_secret: deploy_ssh_key_passphrase - DEPLOY_PRIVATE_KEY: - from_secret: deploy_ssh_key - commands: - - sed -i 's/{{ SPT_ITEMS_HOSTNAME }}/'"$SPT_ITEMS_HOSTNAME"'/g' ./items/frontend/.env.example - - mv ./items/frontend/.env.example ./items/frontend/.env - - echo "$DEPLOY_PRIVATE_KEY" > private.key && chmod 600 private.key - - sed -i 's/{{ DEPLOY_HOSTNAME }}/'"$DEPLOY_HOSTNAME"'/g' ./.ansible-items/inventory - - sed -i 's/{{ DEPLOY_SSH_KEY_PASSPHRASE }}/'"$DEPLOY_SSH_KEY_PASSPHRASE"'/g' ./.ansible-items/inventory - - sed -i 's/{{ DEPLOY_USER }}/'"$DEPLOY_USER"'/g' ./.ansible-items/inventory + - name: replace hosts and user variables + image: ubuntu:impish + environment: + SPT_ITEMS_HOSTNAME: + from_secret: spt_items_hostname + DEPLOY_HOSTNAME: + from_secret: deploy_hostname + DEPLOY_USER: + from_secret: deploy_username + DEPLOY_PRIVATE_KEY: + from_secret: deploy_ssh_key + DEPLOY_SSH_KEY_PASSPHRASE: + from_secret: deploy_ssh_key_passphrase + commands: + - sed -i 's/{{ SPT_ITEMS_HOSTNAME }}/'"$SPT_ITEMS_HOSTNAME"'/g' ./items/frontend/.env.example + - mv ./items/frontend/.env.example ./items/frontend/.env + - echo "$DEPLOY_PRIVATE_KEY" > private.key && chmod 600 private.key + - sed -i 's/{{ DEPLOY_HOSTNAME }}/'"$DEPLOY_HOSTNAME"'/g' ./.ansible-items/inventory + - sed -i 's/{{ DEPLOY_SSH_KEY_PASSPHRASE }}/'"$DEPLOY_SSH_KEY_PASSPHRASE"'/g' ./.ansible-items/inventory + - sed -i 's/{{ DEPLOY_USER }}/'"$DEPLOY_USER"'/g' ./.ansible-items/inventory -- name: build frontend - image: node:lts-alpine3.14 - commands: - - node -v - - npm -v - - yarn --version - - yarn --cwd ./items/frontend install - - yarn --cwd ./items/frontend build --pure-lockfile - - rm -rf ./items/api/public/static/* - - mv ./items/frontend/build/* ./items/api/public - - rm ./items/api/public/index.html + - name: install frontend dependencies + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend install + depends_on: + - replace hosts and user variables -- name: check ansible syntax - image: plugins/ansible:3 - settings: - playbook: ./.ansible-items/playbook.yml - inventory: ./.ansible-items/inventory - galaxy: ./.ansible-items/requirements.yml - syntax_check: true - when: - branch: - - development + - name: frontend + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend start + detach: true + depends_on: + - install frontend dependencies -- name: apply ansible playbook - image: plugins/ansible:3 - settings: - playbook: ./.ansible-items/playbook.yml - inventory: ./.ansible-items/inventory - galaxy: ./.ansible-items/requirements.yml - timeout: 60 - verbose: 2 - environment: - DEPLOY_HOSTNAME: - from_secret: deploy_hostname - SPT_ITEMS_HOSTNAME: - from_secret: spt_items_hostname - DEPLOY_USER: - from_secret: deploy_username - DEPLOY_USER_GROUP: - from_secret: deploy_user_group - SPT_ITEMS_PATH: - from_secret: deploy_path - when: - branch: - - master - - main \ No newline at end of file + - name: test frontend + image: cypress/browsers:node16.5.0-chrome94-ff93 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend cy:run + depends_on: + - install frontend dependencies + + - name: build frontend + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend build --pure-lockfile + - rm -rf ./items/api/public/static/* + - mv ./items/frontend/build/* ./items/api/public + - rm ./items/api/public/index.html + depends_on: + - test frontend + when: + branch: + - main + - master + - development + + - name: check ansible syntax + image: plugins/ansible:3 + settings: + playbook: ./.ansible-items/playbook.yml + inventory: ./.ansible-items/inventory + galaxy: ./.ansible-items/requirements.yml + syntax_check: true + when: + branch: + - development + + - name: apply ansible playbook + image: plugins/ansible:3 + settings: + playbook: ./.ansible-items/playbook.yml + inventory: ./.ansible-items/inventory + galaxy: ./.ansible-items/requirements.yml + timeout: 60 + verbose: 2 + environment: + SPT_ITEMS_HOSTNAME: + from_secret: spt_items_hostname + DEPLOY_HOSTNAME: + from_secret: deploy_hostname + DEPLOY_USER: + from_secret: deploy_username + DEPLOY_USER_GROUP: + from_secret: deploy_user_group + SPT_ITEMS_PATH: + from_secret: deploy_path + depends_on: + - check ansible syntax + - build frontend + when: + branch: + - master + - main \ No newline at end of file diff --git a/.drone-kubernetes.yml b/.drone-kubernetes.yml index d2f8b75..a9239a1 100644 --- a/.drone-kubernetes.yml +++ b/.drone-kubernetes.yml @@ -8,76 +8,112 @@ concurrency: trigger: event: - push - branch: - - master - - main - - development steps: -- name: replace hosts and user variables - image: ubuntu:impish - environment: - SPT_ITEMS_HOSTNAME: - from_secret: spt_items_hostname - DEPLOY_HOSTNAME: - from_secret: deploy_hostname - DEPLOY_USER: - from_secret: deploy_username - DEPLOY_PRIVATE_KEY: - from_secret: deploy_ssh_key - DEPLOY_SSH_KEY_PASSPHRASE: - from_secret: deploy_ssh_key_passphrase - commands: - - sed -i 's/{{ SPT_ITEMS_HOSTNAME }}/'"$SPT_ITEMS_HOSTNAME"'/g' ./items/frontend/.env.example - - mv ./items/frontend/.env.example ./items/frontend/.env - - echo "$DEPLOY_PRIVATE_KEY" > private.key && chmod 600 private.key - - sed -i 's/{{ DEPLOY_HOSTNAME }}/'"$DEPLOY_HOSTNAME"'/g' ./.ansible-items/inventory - - sed -i 's/{{ DEPLOY_SSH_KEY_PASSPHRASE }}/'"$DEPLOY_SSH_KEY_PASSPHRASE"'/g' ./.ansible-items/inventory - - sed -i 's/{{ DEPLOY_USER }}/'"$DEPLOY_USER"'/g' ./.ansible-items/inventory + - name: replace hosts and user variables + image: ubuntu:impish + environment: + SPT_ITEMS_HOSTNAME: + from_secret: spt_items_hostname + DEPLOY_HOSTNAME: + from_secret: deploy_hostname + DEPLOY_USER: + from_secret: deploy_username + DEPLOY_PRIVATE_KEY: + from_secret: deploy_ssh_key + DEPLOY_SSH_KEY_PASSPHRASE: + from_secret: deploy_ssh_key_passphrase + commands: + - sed -i 's/{{ SPT_ITEMS_HOSTNAME }}/'"$SPT_ITEMS_HOSTNAME"'/g' ./items/frontend/.env.example + - mv ./items/frontend/.env.example ./items/frontend/.env + - echo "$DEPLOY_PRIVATE_KEY" > private.key && chmod 600 private.key + - sed -i 's/{{ DEPLOY_HOSTNAME }}/'"$DEPLOY_HOSTNAME"'/g' ./.ansible-items/inventory + - sed -i 's/{{ DEPLOY_SSH_KEY_PASSPHRASE }}/'"$DEPLOY_SSH_KEY_PASSPHRASE"'/g' ./.ansible-items/inventory + - sed -i 's/{{ DEPLOY_USER }}/'"$DEPLOY_USER"'/g' ./.ansible-items/inventory -- name: build frontend - image: node:lts-alpine3.14 - commands: - - node -v - - npm -v - - yarn --version - - yarn --cwd ./items/frontend install - - yarn --cwd ./items/frontend build --pure-lockfile - - rm -rf ./items/api/public/static/* - - mv ./items/frontend/build/* ./items/api/public - - rm ./items/api/public/index.html + - name: install frontend dependencies + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend install + depends_on: + - replace hosts and user variables -- name: check ansible syntax - image: plugins/ansible:3 - settings: - playbook: ./.ansible-items/playbook.yml - inventory: ./.ansible-items/inventory - galaxy: ./.ansible-items/requirements.yml - syntax_check: true - when: - branch: - - development + - name: frontend + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend start + detach: true + depends_on: + - install frontend dependencies -- name: apply ansible playbook - image: plugins/ansible:3 - settings: - playbook: ./.ansible-items/playbook.yml - inventory: ./.ansible-items/inventory - galaxy: ./.ansible-items/requirements.yml - timeout: 60 - verbose: 2 - environment: - SPT_ITEMS_HOSTNAME: - from_secret: spt_items_hostname - DEPLOY_HOSTNAME: - from_secret: deploy_hostname - DEPLOY_USER: - from_secret: deploy_username - DEPLOY_USER_GROUP: - from_secret: deploy_user_group - SPT_ITEMS_PATH: - from_secret: deploy_path - when: - branch: - - master - - main \ No newline at end of file + - name: test frontend + image: cypress/browsers:node16.5.0-chrome94-ff93 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend cy:run + depends_on: + - install frontend dependencies + + - name: build frontend + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend build --pure-lockfile + - rm -rf ./items/api/public/static/* + - mv ./items/frontend/build/* ./items/api/public + - rm ./items/api/public/index.html + depends_on: + - test frontend + when: + branch: + - main + - master + - development + + - name: check ansible syntax + image: plugins/ansible:3 + settings: + playbook: ./.ansible-items/playbook.yml + inventory: ./.ansible-items/inventory + galaxy: ./.ansible-items/requirements.yml + syntax_check: true + when: + branch: + - development + + - name: apply ansible playbook + image: plugins/ansible:3 + settings: + playbook: ./.ansible-items/playbook.yml + inventory: ./.ansible-items/inventory + galaxy: ./.ansible-items/requirements.yml + timeout: 60 + verbose: 2 + environment: + SPT_ITEMS_HOSTNAME: + from_secret: spt_items_hostname + DEPLOY_HOSTNAME: + from_secret: deploy_hostname + DEPLOY_USER: + from_secret: deploy_username + DEPLOY_USER_GROUP: + from_secret: deploy_user_group + SPT_ITEMS_PATH: + from_secret: deploy_path + depends_on: + - check ansible syntax + - build frontend + when: + branch: + - master + - main \ No newline at end of file diff --git a/items/README.md b/items/README.md index 181e465..7780074 100644 --- a/items/README.md +++ b/items/README.md @@ -32,9 +32,12 @@ ## The pipeline summary 1. Each push will: - 1. Builds the frontend - 1. Move the build frontend in the backend `public` folder -1. IF Promoted to production, deploys to the server + 1. Test the frontend + 2. IF on `development` or `master`/`main` branch + 1. Builds the frontend + 3. IF pushed from `master` or `main` main branch + 1. Move the build frontend in the backend `public` folder + 2. Deploys to the server ## The pipeline walkthrough see [Walkthrough.md](./docs/Walkthrough.md) diff --git a/items/docs/Walkthrough.md b/items/docs/Walkthrough.md index 85ef636..4ec88bc 100644 --- a/items/docs/Walkthrough.md +++ b/items/docs/Walkthrough.md @@ -6,8 +6,10 @@ * [Pipeline concurrency](#pipeline-concurrency) * [Triggers](#triggers) * [Steps](#steps) - * [Fetch and update submodules](#Fetch-and-update-submodules) * [Replace hosts and user variables](#replace-hosts-and-user-variables) + * [Install frontend dependencies](#install-frontend-dependencies) + * [Run the frontend](#run-the-frontend) + * [Test frontend](#test-frontend) * [Build frontend](#build-frontend) * [Check ansible syntax](#check-ansible-syntax) * [Apply ansible playbook](#apply-ansible-playbook) @@ -16,8 +18,8 @@ * [Copy the project](#copy-the-project) * [Copy PHP env file](#copy-php-env-file) * [Get JavaScript chunks name](#get-javascript-chunks-name) - * [Get file names from find output](#get-file-from-find-output) - * [Copy app.blade.php file](#copy-app-blade-php-file) + * [Get file names from find output](#get-file-names-from-find-output) + * [Copy app.blade.php file](#copy-appbladephp-file) * [Download and install composer dependencies](#download-and-install-composer-dependencies) ## Overview @@ -25,10 +27,10 @@ * the backend is a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) located in [api](../api) that points towards [https://dev.sp-tarkov.com/Rev/spt-items-api.git](https://dev.sp-tarkov.com/Rev/spt-items-api.git) * the frontend is a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) located in [frontend](../frontend) that points towards [https://dev.sp-tarkov.com/shirito/item-finder-website-frontend.git](https://dev.sp-tarkov.com/shirito/item-finder-website-frontend.git) * There are two Ansible pipelines - * A docker pipeline [drone-docker.yml](../drone-docker.yml) - * A kubernetes pipeline [drone-kubernetes.yml](../drone-kubernetes.yml) -* All ansible playbook files are located in [.ansible](../.ansible) -* The documentation is located in [documentation](../documentation) + * A docker pipeline [drone-docker.yml](../../.drone-docker.yml) + * A kubernetes pipeline [drone-kubernetes.yml](../../.drone-kubernetes.yml) +* All ansible playbook files are located in [.ansible](../../.ansible-items) +* The documentation is located in [documentation](../docs) ## Pipeline definition ```yml @@ -50,12 +52,8 @@ The pipeline is set to only one build at a time (every subsequent build with be trigger: event: - push - branch: - - master - - main - - development ``` -The pipeline is run on every push only on branches `master`, `main` and `development`. We want to check that every development on `development` branch is correct and deploy automatically when merged in `master`/`main`. +The pipeline is run on every push We want to check that every development on `development` branch is correct and deploy automatically when merged in `master`/`main`. ## Steps ### Replace hosts and user variables ```yml @@ -90,6 +88,48 @@ The following environment variables are injected using Drone secrets: Using `sed` makes temporary changes in the container/pod instead of commiting secrets in the repo in plain text. \ The changes are never pushed and are discarded when the container/pod is terminated. +### Install frontend dependencies +```yml +- name: install frontend dependencies + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend install + depends_on: + - replace hosts and user variables +``` + +### Run the frontend +```yaml +- name: frontend + image: node:lts-alpine3.14 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend start + detach: true + depends_on: + - install frontend dependencies +``` +The frontend is run and `detach` is specified so the End-to-End tests (using cypress) can run on it + +### Test frontend +```yaml +- name: test frontend + image: cypress/browsers:node16.5.0-chrome94-ff93 + commands: + - node -v + - npm -v + - yarn --version + - yarn --cwd ./items/frontend cy:run + depends_on: + - install frontend dependencies +``` +Run frontend tests using Cypress + ### Build frontend ```yml - name: build frontend @@ -98,7 +138,6 @@ The changes are never pushed and are discarded when the container/pod is termina - node -v - npm -v - yarn --version - - yarn --cwd ./items/frontend install - yarn --cwd ./items/frontend build --pure-lockfile - rm -rf ./items/api/public/static/* - mv ./items/frontend/build/* ./items/api/public @@ -122,7 +161,7 @@ Notes: syntax_check: true ``` Executed on every push. \ -Check the Ansible syntax in [playbook.yml](../.ansible/playbook.yml), [inventory](../.ansible/inventory) and [requirements.yml](../.ansible/requirements.yml). The check is executed on every push since we want to detect any error before validating the build using the promotion. +Check the Ansible syntax in [playbook.yml](../../.ansible-items/playbook.yml), [inventory](../../.ansible-items/inventory) and [requirements.yml](../../.ansible-items/requirements.yml). The check is executed on every push since we want to detect any error before validating the build using the promotion. ### Apply ansible playbook ```yml @@ -164,7 +203,7 @@ The following environment variables are injected using Drone secrets: ```yml hosts: sptarkov ``` -Uses the host defined in [inventory](../.ansible/inventory). Remember, the step [Replace hosts and user variables](#replace-hosts-and-user-variables) already replaced the variables at this point. +Uses the host defined in [inventory](../../.ansible-items/inventory). Remember, the step [Replace hosts and user variables](#replace-hosts-and-user-variables) already replaced the variables at this point. #### Delete old spt-items-api ```yml @@ -192,7 +231,7 @@ Copies the whole project (frontend and backend) from the [api](../api) folder in src: ./templates/.php-env.j2 dest: "{{ lookup('env', 'SPT_ITEMS_PATH') }}/.env" ``` -Uses [Jinja2](https://jinja2docs.readthedocs.io/en/stable/) to resolve the [template for the PHP .env file](../.ansible/templates/.php_env.j2). \ +Uses [Jinja2](https://jinja2docs.readthedocs.io/en/stable/) to resolve the [template for the PHP .env file](../../.ansible-items/templates/.php-env.j2). \ `SPT_ITEMS_PATH` is injected in the environments properties (see [Apply ansible playbook](#apply-ansible-playbook)) \ `SPT_ITEMS_HOSTNAME` is injected in the environments properties (see [Apply ansible playbook](#apply-ansible-playbook)) @@ -203,7 +242,7 @@ Uses [Jinja2](https://jinja2docs.readthedocs.io/en/stable/) to resolve the [temp cmd: find "{{ lookup('env', 'SPT_ITEMS_PATH') }}" -type f -name "*chunk.js" -printf "%f\n" register: find_output ``` -Prepare a find of all JavaScript chunk files for the [app.blade.php.j2](../.ansible/templates/app.blade.php.j2) template. \ +Prepare a find of all JavaScript chunk files for the [app.blade.php.j2](../../.ansible-items/templates/app.blade.php.j2) template. \ `SPT_ITEMS_PATH` is injected in the environments properties (see [Apply ansible playbook](#apply-ansible-playbook)) #### Get file names from find output @@ -212,7 +251,7 @@ Prepare a find of all JavaScript chunk files for the [app.blade.php.j2](../.ansi set_fact: chunk_list: "{{ find_output['stdout'].split('\n') }}" ``` -Splits the string containing the list of all JavaScript chunk files for the [app.blade.php.j2](../.ansible/templates/app.blade.php.j2) template. +Splits the string containing the list of all JavaScript chunk files for the [app.blade.php.j2](../../.ansible-items/templates/app.blade.php.j2) template. #### Copy app.blade.php file ```yml @@ -221,7 +260,7 @@ Splits the string containing the list of all JavaScript chunk files for the [app src: ./templates/app.blade.php.j2 dest: "{{ lookup('env', 'SPT_ITEMS_PATH') }}/resources/views/app.blade.php" ``` -Uses [Jinja2](https://jinja2docs.readthedocs.io/en/stable/) to resolve the [template for the PHP app.blade.php file](../.ansible/templates/app.blade.php.j2). \ +Uses [Jinja2](https://jinja2docs.readthedocs.io/en/stable/) to resolve the [template for the PHP app.blade.php file](../../.ansible-items/templates/app.blade.php.j2). \ `SPT_ITEMS_PATH` is injected in the environments properties (see [Apply ansible playbook](#apply-ansible-playbook)). #### Download and install composer dependencies diff --git a/items/frontend/cypress.json b/items/frontend/cypress.json index dcc4426..99278a6 100644 --- a/items/frontend/cypress.json +++ b/items/frontend/cypress.json @@ -1,5 +1,6 @@ { "baseUrl": "http://localhost:3000", + "video": false, "integrationFolder": "src/cypress/integration", "fixtureFolder": "src/cypress/fixtures", "supportFile": "src/cypress/support/index.js", diff --git a/items/frontend/cypress/fixtures/example.json b/items/frontend/cypress/fixtures/example.json deleted file mode 100644 index 02e4254..0000000 --- a/items/frontend/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/items/frontend/package.json b/items/frontend/package.json index 70df6b5..460cf14 100644 --- a/items/frontend/package.json +++ b/items/frontend/package.json @@ -13,8 +13,10 @@ "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "cross-env": "^7.0.3", - "cypress": "^8.6.0", - "start-server-and-test": "^1.14.0" + "cypress": "9.0.0", + "start-server-and-test": "^1.14.0", + "typescript": "^4.1.2", + "wait-on": "^6.0.0" }, "dependencies": { "@emotion/react": "^11.4.1", @@ -22,11 +24,12 @@ "@mui/icons-material": "^5.0.3", "@mui/material": "^5.0.3", "@mui/styles": "^5.0.1", + "history": "5", "react": "^17.0.2", "react-dom": "^17.0.2", "react-json-view": "^1.21.3", + "react-router-dom": "6", "react-scripts": "4.0.3", - "typescript": "^4.1.2", "web-vitals": "^1.0.1", "zustand": "^3.5.13" }, @@ -36,8 +39,11 @@ "test:jest": "react-scripts test", "cy:start:app": "cross-env BROWSER=none react-scripts -r @cypress/instrument-cra start", "cy:start:wait": "start-server-and-test cy:start:app http://localhost:3000", + "cy:install": "cypress install", + "cy:verify": "cypress verify", + "cy:run:ci": "cross-env CYPRESS_BASE_URL=http://frontend:3000 cypress run --browser chrome", "cy:open": "yarn run cy:start:wait -- \"cypress open\"", - "cy:run": "yarn run cy:start:wait -- \"cypress run\"", + "cy:run": "yarn run wait-on http-get://frontend:3000 && yarn run cy:install && yarn run cy:verify && yarn run cy:run:ci", "eject": "react-scripts eject" }, "eslintConfig": { @@ -59,8 +65,13 @@ ] }, "nyc": { - "include":["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["src/reportWebVitals.ts"], + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": [ + "src/reportWebVitals.ts" + ], "excludeAfterRemap": true } } diff --git a/items/frontend/src/components/Footer.tsx b/items/frontend/src/components/Footer.tsx index 82a1f97..e2f7541 100644 --- a/items/frontend/src/components/Footer.tsx +++ b/items/frontend/src/components/Footer.tsx @@ -1,23 +1,23 @@ -import { Box, Theme, Typography } from '@mui/material' -import { makeStyles } from '@mui/styles' +import {Box, Typography} from '@mui/material' +import {makeStyles} from '@mui/styles' -const useStyles = makeStyles((theme: Theme) => ({ - footerHolder: { - display: 'flex', - flex: '0 1 3vh', - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - padding: '0 10vw 0 10vw' - } +const useStyles = makeStyles(() => ({ + footerHolder: { + display: 'flex', + flex: '0 1 3vh', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + padding: '0 10vw 0 10vw' + } })) export const Footer = () => { - const classes = useStyles() + const classes = useStyles() - return ( - - SPT-Aki ©2021 Created by Rev and Shirito - - ) + return ( + + SPT-Aki ©2021 Created by Rev and Shirito + + ) } diff --git a/items/frontend/src/cypress/fixtures/condensed_milk.json b/items/frontend/src/cypress/fixtures/condensed_milk.json new file mode 100644 index 0000000..8493398 --- /dev/null +++ b/items/frontend/src/cypress/fixtures/condensed_milk.json @@ -0,0 +1,84 @@ +{ + "item": { + "_id": "5734773724597737fd047c14", + "_name": "condensed_milk", + "_parent": "5448e8d04bdc2ddf718b4569", + "_props": { + "AllowSpawnOnLocations": [], + "AnimationVariantsNumber": 0, + "BackgroundColor": "orange", + "CanRequireOnRagfair": true, + "CanSellOnRagfair": true, + "ChangePriceCoef": 1, + "ConflictingItems": [], + "CreditsPrice": 24943, + "Description": "Condensed milk", + "DiscardingBlock": false, + "ExamineExperience": 20, + "ExamineTime": 1, + "ExaminedByDefault": false, + "ExtraSizeDown": 0, + "ExtraSizeForceAdd": false, + "ExtraSizeLeft": 0, + "ExtraSizeRight": 0, + "ExtraSizeUp": 0, + "FixedPrice": false, + "Height": 1, + "HideEntrails": false, + "IsAlwaysAvailableForInsurance": false, + "IsLockedafterEquip": false, + "IsUnbuyable": false, + "IsUndiscardable": false, + "IsUngivable": false, + "IsUnsaleable": false, + "ItemSound": "food_tin_can", + "LootExperience": 50, + "MaxResource": 1, + "MergesWithChildren": false, + "Name": "Condensed milk", + "NotShownInSlot": false, + "Prefab": { + "path": "assets/content/weapons/usable_items/item_food_condensed_milk/item_food_condensed_milk_loot.bundle", + "rcid": "" + }, + "QuestItem": false, + "RagFairCommissionModifier": 1, + "Rarity": "Rare", + "RepairCost": 0, + "RepairSpeed": 0, + "SendToClient": false, + "ShortName": "Condensed milk", + "SpawnChance": 9, + "StackMaxSize": 1, + "StackObjectsCount": 1, + "StimulatorBuffs": "Buffs_food_condensed_milk", + "Unlootable": false, + "UnlootableFromSide": [], + "UnlootableFromSlot": "FirstPrimaryWeapon", + "UsePrefab": { + "path": "assets/content/weapons/usable_items/item_food_condensed_milk/item_food_condensed_milk_container.bundle", + "rcid": "" + }, + "Weight": 0.4, + "Width": 1, + "effects_damage": [], + "effects_health": { + "Energy": { + "value": 75 + }, + "Hydration": { + "value": -65 + } + }, + "foodEffectType": "afterUse", + "foodUseTime": 4 + }, + "_proto": "5734770f24597738025ee254", + "_type": "Item" + }, + "locale": { + "Description": "Condensed milk, also called \"Sguschyonka\" in Russia, once was a part of field ration for the Union soldiers in Civil War, but later reached unprecedented popularity in post-Soviet countries, becoming almost a staple product. Canned, it can be stored for decades and remain just as sweet, tasty and nutritious.", + "Name": "Condensed milk", + "ShortName": "Cond. milk" + } +} \ No newline at end of file diff --git a/items/frontend/src/cypress/integration/footer.spec.tsx b/items/frontend/src/cypress/integration/footer.spec.tsx index ec80972..74ebb72 100644 --- a/items/frontend/src/cypress/integration/footer.spec.tsx +++ b/items/frontend/src/cypress/integration/footer.spec.tsx @@ -4,7 +4,7 @@ describe('Footer', () => { it('footer should be visible', () => { cy.visit('/'); - cy.get('.makeStyles-footerHolder-63 > .MuiTypography-root').should('be.visible') - cy.get('.makeStyles-footerHolder-63 > .MuiTypography-root').should('have.text', 'SPT-Aki ©2021 Created by Rev and Shirito'); + cy.get('#footer').should('be.visible') + cy.get('#footer').should('have.text', 'SPT-Aki ©2021 Created by Rev and Shirito'); }) }) diff --git a/items/frontend/src/cypress/integration/search.spec.tsx b/items/frontend/src/cypress/integration/search.spec.tsx index 9c7c60b..51ee3be 100644 --- a/items/frontend/src/cypress/integration/search.spec.tsx +++ b/items/frontend/src/cypress/integration/search.spec.tsx @@ -1,11 +1,32 @@ +import condensedMilk from "../fixtures/condensed_milk.json"; + export {}; describe('Search area', ()=>{ beforeEach(() => { - cy.intercept('GET','**/api/locales', { + cy.intercept({ + method: 'GET', + url: '**/api/locales' + }, { statusCode: 200, body: ['locale1', 'locale2'] - }); + }).as('getLocalesWithoutData'); + + cy.intercept({ + method: 'GET', + url: '**/api/item?*' + }, { + statusCode: 200, + body: condensedMilk + }) + + cy.intercept({ + method: 'GET', + url: '**/api/item/hierarchy*' + }, { + statusCode: 200, + body: condensedMilk + }) cy.visit('/'); }) @@ -31,4 +52,19 @@ describe('Search area', ()=>{ .should('be.visible') .contains('p', 'No data to display'); }) + + describe('Searching', () => { + it('Search using ID displays the json with locale', () => { + cy.get('#search-autocomplete') + .type(condensedMilk.item._id) + .type('{ENTER}') + .should('have.value', condensedMilk.locale.Name) + cy.get(`.react-json-view .object-key-val > .pushed-content > .object-content > .variable-row > .variable-value > div > .string-value:contains("${condensedMilk.item._id}")`) + .should('have.length', 1) + .invoke('text') + .should('eq', `"${condensedMilk.item._id}"`); + cy.get(`.react-json-view .object-key-val > .pushed-content > .object-content > .variable-row > .variable-value > div > .string-value:contains("${condensedMilk.locale.Name}")`) + .should('have.length.above', 0); + }) + }) }) \ No newline at end of file diff --git a/items/frontend/src/cypress/integration/url-check.spec.tsx b/items/frontend/src/cypress/integration/url-check.spec.tsx new file mode 100644 index 0000000..802a7dd --- /dev/null +++ b/items/frontend/src/cypress/integration/url-check.spec.tsx @@ -0,0 +1,73 @@ +export {}; + +import condensedMilk from '../fixtures/condensed_milk.json' + +describe('Url check', () => { + beforeEach(() => { + cy.window() + .its("sessionStorage") + .invoke("removeItem", "items.sp-tarkov.com-locales"); + + cy.intercept({ + method: 'GET', + url: '**/api/locales' + }, { + statusCode: 200, + body: [] + }).as('getLocalesWithoutData'); + + cy.intercept({ + method: 'GET', + url: '**/api/item?*' + }, { + statusCode: 200, + body: condensedMilk + }) + + cy.intercept({ + method: 'GET', + url: '**/api/item/hierarchy*' + }, { + statusCode: 200, + body: condensedMilk + }) + }) + + afterEach(() => { + cy.clearLocalStorage(); + }) + + describe('Check page not found', () => { + it('Invalid url should redirect to page not found', () => { + cy.visit('/ABC') + cy.get('#not-found-message').contains("This page does not exist !"); + }) + }) + + describe('Check root redirection', () => { + it('Root should redirect to search', () => { + cy.visit('/') + cy.url().should("include", "/search"); + }) + }) + + describe('Check url changes with search input', () => { + it('ID in url applies search', () => { + cy.visit(`/search/${condensedMilk.item._id}`); + cy.get('#search-autocomplete').should('have.value', condensedMilk.locale.Name) + }) + + it('Search reflects in url', () => { + cy.visit(`/`); + cy.get('#search-autocomplete') + .type(condensedMilk.item._id) + .type('{ENTER}') + .should('have.value', condensedMilk.locale.Name); + cy.url().should("include", `/search/${condensedMilk.item._id}`); + cy.get(`.react-json-view .object-key-val > .pushed-content > .object-content > .variable-row > .variable-value > div > .string-value:contains("${condensedMilk.item._id}")`) + .should('have.length', 1) + .invoke('text') + .should('eq', `"${condensedMilk.item._id}"`); + }) + }) +}) \ No newline at end of file diff --git a/items/frontend/src/index.tsx b/items/frontend/src/index.tsx index 7998135..6031b20 100644 --- a/items/frontend/src/index.tsx +++ b/items/frontend/src/index.tsx @@ -4,13 +4,13 @@ import App from './App'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( - - - , - document.getElementById('root') + + + , + document.getElementById('root') ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +reportWebVitals(); \ No newline at end of file diff --git a/items/frontend/src/pages/InteractiveArea.tsx b/items/frontend/src/pages/InteractiveArea.tsx new file mode 100644 index 0000000..34a79d7 --- /dev/null +++ b/items/frontend/src/pages/InteractiveArea.tsx @@ -0,0 +1,26 @@ +import {Box} from '@mui/material' +import {NavigationBreadcrumb} from './mainPageComponents/NavigationBreadcrumb' +import {SearchArea} from './mainPageComponents/SearchArea' +import {makeStyles} from "@mui/styles"; +import React from "react"; + +const useStyles = makeStyles(() => ({ + searchContainer: { + display: 'flex', + flexDirection: 'row', + flexGrow: 1, + padding: '2vh 2vw 1vh 2vw' + } +})) + +export const InteractiveArea = () => { + const classes = useStyles(); + return ( + <> + + + + + + ) +} diff --git a/items/frontend/src/pages/MainPage.tsx b/items/frontend/src/pages/MainPage.tsx index a5c3b33..4d92486 100644 --- a/items/frontend/src/pages/MainPage.tsx +++ b/items/frontend/src/pages/MainPage.tsx @@ -1,11 +1,13 @@ -import {Box, Theme} from '@mui/material' +import {Box} from '@mui/material' import {Footer} from '../components/Footer' import {Header} from '../components/Header' -import {NavigationBreadcrumb} from './mainPageComponents/NavigationBreadcrumb' -import {SearchArea} from './mainPageComponents/SearchArea' import {makeStyles} from "@mui/styles"; +import {BrowserRouter, Navigate, Route, Routes} from "react-router-dom"; +import React from "react"; +import {InteractiveArea} from "./InteractiveArea"; +import {PageNotFound} from "./PageNotFound"; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles(() => ({ container: { background: 'background.default', display: 'flex', @@ -13,12 +15,6 @@ const useStyles = makeStyles((theme: Theme) => ({ flexGrow: 1, height: '100vh', maxheight: '100vh', - }, - searchContainer: { - display: 'flex', - flexDirection: 'row', - flexGrow: 1, - padding: '2vh 2vw 1vh 2vw' } })) @@ -28,10 +24,15 @@ export const MainPage = () => { <>
- - - - + + + }> + }/> + + }/> + }/> + +