Skip to content
Snippets Groups Projects
Commit f5cef999 authored by Ina Martini's avatar Ina Martini
Browse files

fix: commit

parent caabf0df
No related branches found
No related tags found
3 merge requests!66Final merge,!57General cleanup of application,!4Pipeline fix
Showing with 8168 additions and 0 deletions
# Dependency directories
/node_modules
# Distribution directories
/dist
/build
# Environment files
.env.*
# Editor directories and files
.vscode
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Cache directories
/.cache
# Test directories
/coverage
/cypress/videos/
/cypress/screenshots/
# Temporary files
*.temp
# System files
.DS_Store
Thumbs.db
\ No newline at end of file
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
overrides: [
{
files: [
'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}',
'cypress/support/**/*.{js,ts,jsx,tsx}'
],
'extends': [
'plugin:cypress/recommended'
]
}
],
parserOptions: {
ecmaVersion: 'latest'
}
}
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
image: node:20-slim
stages:
- install
- lint_and_format
- build
- test
- security_scan
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
install:
stage: install
script:
- npm install
artifacts:
paths:
- node_modules/
format-code:
stage: lint_and_format
script:
- npm run format-test
lint-code:
stage: lint_and_format
script:
- npm run lint
type-check:
stage: build
script:
- npm run type-check
- npm run build
unit-tests:
stage: test
script:
- npm run test:unit
test:e2e:
image: cypress/browsers:node16.14.2-slim-chrome100-ff99-edge
stage: test
script:
- npm ci --cache .npm --prefer-offline
- npx cypress verify
- npm run test:e2e
dependencies:
- install
test-coverage:
stage: test
script:
- npm run test:coverage
include:
- template: SAST.gitlab-ci.yml
sast:
stage: security_scan
script:
- echo "Running SAST..."
\ No newline at end of file
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 4,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none",
"endOfLine": "lf"
}
\ No newline at end of file
{
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
FROM node:21.5.0
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD [ "npm", "run", "dev" ]
\ No newline at end of file
Makefile 0 → 100644
.PHONY: build run run-dev unit e2e clean-docker
build-docker:
docker build -t sparesti_frontend .
run-docker:
docker run --rm --name sparesti_frontend_container -p 5173:5173 sparesti_frontend
clean-docker:
-docker stop sparesti_frontend_container
-docker rm sparesti_frontend_container
run:
make build-docker
make clean-docker
make run-docker
run-dev:
npm run dev
unit:
npm run test:unit
e2e:
npm run test:e2e
# idatt2106_2024_02_frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
npm run test:unit
```
### Run End-to-End Tests with [Cypress](https://www.cypress.io/)
```sh
npm run test:e2e:dev
```
This runs the end-to-end tests against the Vite development server.
It is much faster than the production build.
But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments):
```sh
npm run build
npm run test:e2e
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:4173/',
video: false,
},
env: {
apiUrl: 'http://localhost:8080/',
},
});
\ No newline at end of file
/*import { useUserStore } from '../../src/stores/userStore'
describe('Goals and Challenges Page Load', () => {
let userStore;
beforeEach(() => {
// Add console log to trace API calls
cy.on('window:before:load', (win) => {
cy.spy(win.console, 'log');
});
cy.window().then((win) => {
win.sessionStorage.setItem('accessToken', 'validAccessToken');
win.localStorage.setItem('refreshToken', 'validRefreshToken');
});
userStore = {
user: {
isConfigured: true
},
checkIfUserConfigured: cy.stub().resolves(),
};
cy.stub(window, useUserStore()).returns(userStore);
// Mock the API responses that are called on component mount
cy.intercept('GET', '/goals', {
statusCode: 200,
body: {
content: [
{ id: 1, title: 'gaming', saved: 150, target: 1000, completion: 15 },
],
},
}).as('fetchGoals');
// Mock the POST request for renewing the token if it's not implemented in the backend
cy.intercept('POST', '/auth/renewToken', {
statusCode: 200,
body: {
accessToken: 'newlyRenewedAccessToken'
}
}).as('renewToken');
cy.intercept('GET', '/challenges', {
statusCode: 200,
body: {
content: [
{ id: 1, title: 'Coffee Challenge', type:'coffee',perPurchase: 20, saved: 60, target: 100, completion: 60 },
],
},
}).as('fetchChallenges');
cy.intercept('GET', '/profile/streak', {
statusCode: 200,
body: {
content: [
{ streak: 1, startDate: "2026-04-29T12:10:38.308Z" },
],
},
}).as('fetchChallenges');
// Visit the component that triggers these requests in `onMounted`
cy.visit('/hjem');
});
it('loads and displays goals and challenges after onMounted', () => {
// Wait for API calls made during `onMounted` to complete
cy.wait(['@fetchGoals', '@fetchChallenges']);
// Mock the POST request for renewing the token if it's not implemented in the backend
cy.intercept('POST', '/auth/renewToken', {
statusCode: 200,
body: {
accessToken: 'newlyRenewedAccessToken'
}
}).as('renewToken');
// Check console logs for any errors or warnings that might indicate issues
cy.window().then((win) => {
expect(win.console.log).to.be.calledWithMatch(/Goals:/); // Adjust based on actual logging in your Vue app
});
// Assertions to verify the DOM is updated correctly
cy.get('[data-cy=goal-title]').should('exist').and('contain', 'gaming');
cy.get('[data-cy=challenge-title]').should('exist').and('contain', 'Coffee Challenge');
});
it('Should increment a challenges progress when the increment button is clicked', () => {
cy.wait('@fetchChallenges');
// Separate aliases for clarity
cy.intercept('PUT', '/challenges/1', {
statusCode: 200,
body: {
id: 1,
title: 'Coffee Challenge',
type: 'coffee',
perPurchase: 20,
saved: 80, // this is the updated amount
target: 100,
completion: 80,
},
}).as('incrementChallenge1');
cy.intercept('PUT', '/goals/1', {
statusCode: 200,
body: { id: 1, title: 'gaming', saved: 170, target: 1000, completion: 15 },
}).as('incrementChallenge');
// Mock the POST request for renewing the token if it's not implemented in the backend
cy.intercept('POST', '/auth/renewToken', {
statusCode: 200,
body: {
accessToken: 'newlyRenewedAccessToken'
}
}).as('renewToken');
cy.get('[data-cy=increment-challenge1]').click();
cy.wait('@incrementChallenge1'); // Wait for the specific challenge update intercept
// Check if the progress bar reflects the right percentage
cy.get('[data-cy=challenge-progress]')
.invoke('attr', 'style')
.should('contain', 'width: 80%'); // Directly check the style attribute for the width
});
it('Should navigate to the spare challenges page when adding a new challenge', () => {
// Mock the routing to the spare challenges page
cy.intercept('GET', '/spareutfordringer', {
statusCode: 200,
body: { content: 'Spare Challenges Page' }
}).as('spareChallenges');
// Trigger the route change
cy.get('[data-cy=challenge-icon-1]').click();
// Assert that navigation has occurred
cy.url().should('include', '/spareutfordringer/rediger/1');
});
});
*/
\ No newline at end of file
describe('Login', () => {
beforeEach(() => {
cy.visit('/logginn')
})
function fullInput() {
cy.get('input[name=username]').type('test')
cy.get('input[name=password]').type('test')
}
it('visits the login page as default', () => {
cy.contains('button', 'Logg inn')
})
it('disables the login button when no input', () => {
cy.contains('button', 'Logg inn').should('be.disabled')
})
it('disables the login button when only username is input', () => {
cy.get('input[name=username]').type('test')
cy.contains('button', 'Logg inn').should('be.disabled')
})
it('disables the login button when only password is input', () => {
cy.get('input[name=password]').type('test')
cy.contains('button', 'Logg inn').should('be.disabled')
})
it('enables the login button when both username and password is input', () => {
fullInput()
cy.contains('button', 'Logg inn').should('not.be.disabled')
})
it('pushes the the user to root page on successful login', () => {
cy.intercept('POST', 'http://localhost:8080/auth/login', {
body: {
accessToken: 'fakeToken',
refreshToken: 'fakeToken'
}
}).as('login')
fullInput()
cy.get('button[name=submit]').click()
cy.wait('@login')
cy.url().should('include', '/')
})
})
describe('Register', () => {
beforeEach(() => {
cy.visit('/registrer')
cy.contains('h3', 'Registrer deg').click()
})
function fullInput() {
cy.get('input[name="firstName"]').type('firstName')
cy.get('input[name="lastName"]').type('lastName')
cy.get('input[name="email"]').type('email@test.work')
cy.get('input[name="username"]').type('username')
cy.get('input[name="password"]').type('Password123!')
cy.get('input[name="confirm"]').type('Password123!')
}
it('visits the register page when clicked', () => {
cy.contains('button[name="submit"]', 'Registrer deg')
})
it('disables the login button when no input', () => {
cy.get('button[name="submit"]').should('be.disabled')
})
it('enable the login button when all inputs are filled and l', () => {
fullInput()
cy.get('button[name="submit"]').should('not.be.disabled')
})
it('pushes the user to the root page on successful register', () => {
cy.intercept('POST', 'http://localhost:8080/auth/register', {
body: {
accessToken: 'fakeToken',
refreshToken: 'fakeToken'
}
}).as('register')
fullInput()
cy.get('button[name="submit"]').click()
cy.wait('@register')
cy.url().should('include', '/')
})
})
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["./**/*", "../support/**/*"],
"compilerOptions": {
"isolatedModules": false,
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
}
}
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
export {}
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
/// <reference types="vite/client" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SpareSti</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment