diff --git a/cypress/e2e/LogIn.cy.ts b/cypress/e2e/LogIn.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5d26ad9b4a82bc34e5817e00a5b2e077b6ac2d7d
--- /dev/null
+++ b/cypress/e2e/LogIn.cy.ts
@@ -0,0 +1,26 @@
+describe('Login spec', () => {
+  it('Can log in', () => {
+    cy.visit('/login')
+
+    cy.get('[data-testid="LogInButton"]').should('be.disabled')
+
+    cy.get('[data-testid="NameInput"]').type("JohnSmith12")
+    cy.get('[data-testid="NameInput"]').should('have.value', "JohnSmith12")
+
+    cy.get('[data-testid="LogInButton"]').should('be.disabled')
+
+    cy.get('[data-testid="PasswordInput"]').type("password")
+    cy.get('[data-testid="PasswordInput"]').should('have.value', "password")
+
+    cy.get('[data-testid="LogInButton"]').should('be.enabled')
+    cy.get('[data-testid="LogInButton"]').click()
+    cy.url().should('include', '/homepage')
+  })
+
+  it('Can navigate to new user', () => {
+    cy.visit('/login')
+    cy.get('[data-testid="NewUserLink"]').click()
+    cy.url().should('include', '/signup')
+
+  })
+})
\ No newline at end of file
diff --git a/src/components/__tests__/BadgeInfo.spec.ts b/src/components/__tests__/BadgeInfo.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..72a293d02f3d4eee4a1c92ab697cb03dd6425be3
--- /dev/null
+++ b/src/components/__tests__/BadgeInfo.spec.ts
@@ -0,0 +1,30 @@
+import { mount } from '@vue/test-utils';
+import BadgeInfo from '@/components/profile/BadgeInfo.vue';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { createPinia, setActivePinia } from 'pinia';
+
+describe('Component', () => {
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('renders badges with correct data', async () => {
+    const wrapper = mount(BadgeInfo, {
+      props: { title: 'Test Title' }
+    });
+
+    await wrapper.vm.$nextTick();
+
+    const badges = wrapper.findAll('.badge');
+
+    badges.forEach((badge, index) => {
+      const achievement = (wrapper.vm as any).achievements[index];
+      const img = badge.find('.badge-img');
+      const title = badge.find('.badge-title');
+
+      expect(img.attributes('src')).toBe(achievement.img);
+      expect(img.attributes('alt')).toBe(achievement.title);
+      expect(title.text()).toBe(achievement.title);
+    });
+  });
+});
diff --git a/src/components/__tests__/BankAccountInfo.spec.ts b/src/components/__tests__/BankAccountInfo.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0aea7c471cf73be88260cefab94974490a6d73b
--- /dev/null
+++ b/src/components/__tests__/BankAccountInfo.spec.ts
@@ -0,0 +1,22 @@
+// Import necessary dependencies
+import { mount } from '@vue/test-utils'
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import BankAccountInfo from '@/components/profile/BankAccountInfo.vue';
+import { createPinia, setActivePinia } from 'pinia'
+
+describe('AccountInfo.vue', () => {
+  let wrapper:any
+
+  beforeEach(() => {
+    setActivePinia(createPinia());
+    wrapper = mount(BankAccountInfo)
+  })
+
+  afterEach(() => {
+    wrapper.unmount()
+  })
+
+  it('renders correctly', () => {
+    expect(wrapper.html()).toMatchSnapshot()
+  })
+})
diff --git a/src/components/__tests__/IncomeInfo.spec.ts b/src/components/__tests__/IncomeInfo.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..779f8b376ee7331cd2b45ca451cf1bd128c16ea2
--- /dev/null
+++ b/src/components/__tests__/IncomeInfo.spec.ts
@@ -0,0 +1,21 @@
+import { mount } from '@vue/test-utils';
+import IncomeInfo from '@/components/profile/IncomeInfo.vue'
+import { describe, it, expect, beforeEach } from 'vitest'
+import { createPinia, setActivePinia } from 'pinia'
+
+describe('IncomeInfo', () => {
+
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('renders correctly', async () => {
+    const wrapper = mount(IncomeInfo);
+
+    expect(wrapper.exists()).toBe(true);
+
+    expect(wrapper.findAll('.input-field')).toHaveLength(3);
+
+    expect(wrapper.find('.save-button').exists()).toBe(true);
+  });
+});
diff --git a/src/components/__tests__/PasswordInfo.spec.ts b/src/components/__tests__/PasswordInfo.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f8e6d79ed7346ef47adb6e1b3c71fe1c136267b6
--- /dev/null
+++ b/src/components/__tests__/PasswordInfo.spec.ts
@@ -0,0 +1,25 @@
+import { mount } from '@vue/test-utils'
+import PasswordInfo from '@/components/profile/PasswordInfo.vue'
+import { describe, it, expect, beforeEach } from 'vitest'
+import { createPinia, setActivePinia } from 'pinia'
+
+describe('PasswordComponent', () => {
+
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('renders correctly', async () => {
+    const wrapper = mount(PasswordInfo)
+
+    expect(wrapper.exists()).toBe(true)
+
+    expect(wrapper.find('.title').text()).toBe('Passord')
+
+    expect(wrapper.find('.save-button').exists()).toBe(true)
+
+    expect(wrapper.find('[data-testid="current-password-input"]').exists()).toBe(true)
+
+    expect(wrapper.find('[data-testid="new-password-input"]').exists()).toBe(true)
+  })
+})
diff --git a/src/components/__tests__/UserInfo.spec.ts b/src/components/__tests__/UserInfo.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8e44d8f598da0cf4c13bc1a4347496c88266e5d5
--- /dev/null
+++ b/src/components/__tests__/UserInfo.spec.ts
@@ -0,0 +1,40 @@
+import { mount } from '@vue/test-utils'
+import UserInfo from '@/components/profile/UserInfo.vue'
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { updateUserInfo } from '../../utils/profileutils'
+
+// Mocking getUserInfo and updateUserInfo functions
+vi.mock('@/utils/profileutils', () => ({
+  getUserInfo: vi.fn(),
+  updateUserInfo: vi.fn()
+}))
+
+// Mocking useTokenStore
+vi.mock('@/stores/token', () => ({
+  useTokenStore: vi.fn(() => ({ jwtToken: 'mockedToken' }))
+}))
+
+describe('UserInfo', () => {
+  let wrapper:any
+
+  beforeEach(() => {
+    wrapper = mount(UserInfo)
+  })
+
+  afterEach(() => {
+    wrapper.unmount()
+  })
+
+  it('saves user info when save button is clicked', async () => {
+    wrapper.vm.email = 'newemail@example.com'
+    wrapper.vm.profilePictureBase64 = 'newBase64String'
+
+    await wrapper.find('.save-button').trigger('click')
+
+    expect(updateUserInfo).toHaveBeenCalledWith(
+      'mockedToken',
+      'newemail@example.com',
+      'newBase64String'
+    )
+  })
+})
diff --git a/src/components/__tests__/__snapshots__/BankAccountInfo.spec.ts.snap b/src/components/__tests__/__snapshots__/BankAccountInfo.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7501cf70f56288cd8cbfb48835ee3a1c1ab1419a
--- /dev/null
+++ b/src/components/__tests__/__snapshots__/BankAccountInfo.spec.ts.snap
@@ -0,0 +1,23 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`AccountInfo.vue > renders correctly 1`] = `
+"<div data-v-d2243dda="" class="account-info">
+  <div data-v-d2243dda="" class="header">
+    <h3 data-v-d2243dda="" class="title">Konto opplysninger</h3><button data-v-d2243dda="" class="save-button">
+      <h3 data-v-d2243dda="" class="save-button-title">Lagre</h3>
+    </button>
+  </div>
+  <div data-v-d2243dda="" class="input-fields">
+    <div data-v-d2243dda="" class="input-collection">
+      <h4 data-v-d2243dda="">Forbrukskonto: </h4><select data-v-d2243dda="" class="accounts"></select>
+    </div>
+    <div data-v-d2243dda="" class="input-collection">
+      <h4 data-v-d2243dda="">Sparekonto: </h4><select data-v-d2243dda="" class="accounts"></select>
+    </div>
+    <div data-v-d2243dda="" class="alert-box">
+      <!--v-if-->
+      <!--v-if-->
+    </div>
+  </div>
+</div>"
+`;
diff --git a/src/components/profile/PasswordInfo.vue b/src/components/profile/PasswordInfo.vue
index dff3599bed71b23e98712a462bb0daf84fd9226e..29dbbceb5ec22b7b014c0c79be4a6301d7de79a0 100644
--- a/src/components/profile/PasswordInfo.vue
+++ b/src/components/profile/PasswordInfo.vue
@@ -73,7 +73,8 @@ const clearInput = () => {
         <input class="input"
                :class="{'error': currentPasswordError}"
                type="password"
-               v-model="currentPassword">
+               v-model="currentPassword"
+               data-testid="current-password-input">
         <div class="alert-box">
           <h4 v-if="currentPasswordError" class="error-message">{{currentPasswordError}}</h4>
         </div>
@@ -84,7 +85,8 @@ const clearInput = () => {
         <input class="input"
                :class="{'error': newPasswordError}"
                type="password"
-               v-model="newPassword">
+               v-model="newPassword"
+               data-testid="new-password-input">
         <div class="alert-box">
           <h4 v-if="newPasswordError" class="error-message">{{newPasswordError}}</h4>
           <h4 v-if="passwordError" class="error-message">{{passwordError}}</h4>
diff --git a/src/views/FrontPage/LoginView.vue b/src/views/FrontPage/LoginView.vue
index 97845e4e6e69d0098d49a33b570bd0a207543de9..f95861ec8541cdbcfc7856d31316c565824dd929 100644
--- a/src/views/FrontPage/LoginView.vue
+++ b/src/views/FrontPage/LoginView.vue
@@ -36,15 +36,22 @@ async function login() {
     <div id="LoginFields">
       <div id="UserDiv">
         <h2 id="Username">Brukernavn</h2>
-        <input id="NameField" placeholder="Skriv inn dit brukernavn" v-model="username">
+        <input id="NameField" placeholder="Skriv inn dit brukernavn" v-model="username" data-testid="NameInput">
       </div>
       <div id="PasswordDiv">
         <h2 id="Password">Passord</h2>
-        <input id="PasswordField" type="password" placeholder="Skriv inn dit passord" v-model="password">
+        <input id="PasswordField" type="password" placeholder="Skriv inn dit passord" v-model="password" data-testid="PasswordInput">
       </div>
     </div>
-    <button id="LogInButton" @click="login" :disabled="!username || password.length < 8" :class="{ 'disabled-button': !username || password.length < 8 }">LogIn</button>
-    <h2 tabindex="0" @keyup.enter="navigateToNewUser()" @click="navigateToNewUser()" id="NewUser">Ny til Sparesti? Trykk her for å lage en profil!</h2>
+
+    <button id="LogInButton"
+            @click="login"
+            :disabled="!username || password.length < 8"
+            :class="{ 'disabled-button': !username || password.length < 8 }"
+            data-testid="LogInButton">
+      LogIn
+    </button>
+    <h2 tabindex="0" @keyup.enter="navigateToNewUser()" @click="navigateToNewUser()" id="NewUser" data-testid="NewUserLink">Ny til Sparesti? Trykk her for å lage en profil!</h2>
   </div>
 </template>