-
Notifications
You must be signed in to change notification settings - Fork 1
Exercise 7 #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Exercise 7 #13
Changes from all commits
db8ca28
91a4e36
6490100
b65c69e
700d19d
bb2ac3b
1bc5a13
544b72c
8c6134e
0fe127a
1285621
271baf2
05cf094
bb045a1
e569b39
6f92197
a4ad086
3d31d5a
d680559
c21b280
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,4 +19,5 @@ npm-debug.log* | |
| storybook-static | ||
|
|
||
| ### Nuxt.js### | ||
| .nuxt | ||
| .nuxt | ||
| static/sw.js | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import { createLocalVue, shallowMount } from "@vue/test-utils"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good job!
|
||
| import Vuex from "vuex"; | ||
| import LoginForm from "./LoginForm.vue"; | ||
|
|
||
| const localVue = createLocalVue(); | ||
| localVue.use(Vuex); | ||
|
|
||
| describe("LoginForm.vue", () => { | ||
| let wrapper; | ||
| let actions; | ||
| let store; | ||
|
|
||
| const createComponent = () => { | ||
| store = new Vuex.Store({ | ||
| actions, | ||
| }); | ||
| wrapper = shallowMount(LoginForm, { | ||
| store, | ||
| localVue, | ||
| }); | ||
| }; | ||
|
|
||
| afterEach(() => { | ||
| wrapper.destroy(); | ||
| }); | ||
|
|
||
| it("renders a Vue component", () => { | ||
| createComponent(); | ||
| expect(wrapper.exists()).toBe(true); | ||
| }); | ||
|
|
||
| it("renders an email input field", () => { | ||
| createComponent(); | ||
| const emailInput = wrapper.find("input#email"); | ||
| expect(emailInput.exists()).toBe(true); | ||
| }); | ||
|
|
||
| it("renders a password input field", () => { | ||
| createComponent(); | ||
| const passwordInput = wrapper.find("input#password"); | ||
| expect(passwordInput.exists()).toBe(true); | ||
| }); | ||
|
|
||
| it("renders a submit button", () => { | ||
| createComponent(); | ||
| const submitBtn = wrapper.find("input#submit"); | ||
| expect(submitBtn.exists()).toBe(true); | ||
| }); | ||
|
|
||
| describe("invalid credentials", () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| let login; | ||
| beforeEach(() => { | ||
| login = jest.fn().mockRejectedValue(new Error("test")); | ||
| actions = { | ||
| login, | ||
| }; | ||
| createComponent(); | ||
| }); | ||
|
|
||
| describe("click submit button", () => { | ||
| beforeEach(() => { | ||
| const submitBtn = wrapper.find("input#submit"); | ||
| submitBtn.trigger("click"); | ||
| }); | ||
| it("calls login", () => { | ||
| expect(login.mock.calls.length).toBe(1); | ||
| }); | ||
| it("renders error message", () => { | ||
| const invCredentialsMsg = wrapper.find("#invCredentialsMsg"); | ||
| expect(invCredentialsMsg.exists()).toBe(true); | ||
| expect(invCredentialsMsg.text()).toContain("Falsche Email oder Passwort"); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,64 @@ | ||||||
| <template> | ||||||
| <div> | ||||||
| <form onsubmit="event.preventDefault();"> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| <input | ||||||
| id="email" | ||||||
| type="email" | ||||||
| aria-label="Email" | ||||||
| v-model="email" | ||||||
| placeholder="Email" | ||||||
| /> | ||||||
| <input | ||||||
| id="password" | ||||||
| type="password" | ||||||
| aria-label="Password" | ||||||
| v-model="password" | ||||||
| placeholder="Password" | ||||||
| /> | ||||||
| <div id="invCredentialsMsg" v-if="invalidCredentials"> | ||||||
| Falsche Email oder Passwort | ||||||
| </div> | ||||||
| <input | ||||||
| id="submit" | ||||||
| type="submit" | ||||||
| aria-label="Login" | ||||||
| value="Login" | ||||||
| @click="submit" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you have the submit on the |
||||||
| /> | ||||||
| </form> | ||||||
| </div> | ||||||
| </template> | ||||||
|
|
||||||
| <script> | ||||||
| import { mapActions } from "vuex"; | ||||||
| export default { | ||||||
| methods: { | ||||||
| ...mapActions(["login"]), | ||||||
| submit: async function () { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| try { | ||||||
| await this.login({ | ||||||
| email: this.email, | ||||||
| password: this.password, | ||||||
| apolloClient: this.$apollo, | ||||||
| }); | ||||||
| this.$router.push({ | ||||||
| path: "/", | ||||||
| }); | ||||||
| this.invalidCredentials = false; | ||||||
| } catch (error) { | ||||||
| this.invalidCredentials = true; | ||||||
| } | ||||||
| }, | ||||||
| }, | ||||||
| data: function () { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| return { | ||||||
| email: "", | ||||||
| password: "", | ||||||
| invalidCredentials: false, | ||||||
| }; | ||||||
| }, | ||||||
| }; | ||||||
| </script> | ||||||
|
|
||||||
| <style> | ||||||
| </style> | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,86 @@ | ||||||||||
| import { createLocalVue, shallowMount, RouterLinkStub } from "@vue/test-utils"; | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks great,
|
||||||||||
| import Vuex from "vuex"; | ||||||||||
| import NavBar from "./NavBar.vue"; | ||||||||||
|
|
||||||||||
| const localVue = createLocalVue(); | ||||||||||
| localVue.use(Vuex); | ||||||||||
|
|
||||||||||
| describe("NavBar.vue", () => { | ||||||||||
| let wrapper; | ||||||||||
| let actions; | ||||||||||
| let getters; | ||||||||||
| let store; | ||||||||||
|
|
||||||||||
| const createComponent = () => { | ||||||||||
| store = new Vuex.Store({ | ||||||||||
| actions, | ||||||||||
| getters, | ||||||||||
| }); | ||||||||||
| wrapper = shallowMount(NavBar, { | ||||||||||
| store, | ||||||||||
| localVue, | ||||||||||
| stubs: { | ||||||||||
| NuxtLink: RouterLinkStub, | ||||||||||
| }, | ||||||||||
| }); | ||||||||||
| }; | ||||||||||
| beforeEach(() => { | ||||||||||
| getters = { | ||||||||||
| loggedIn: () => false, | ||||||||||
| }; | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| afterEach(() => { | ||||||||||
| wrapper.destroy(); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess, if you would return the wrapper in your setup method, you don't run into issues of re-using an existing wrapper. So you wouldn't need this safety measure here. |
||||||||||
| }); | ||||||||||
|
|
||||||||||
| it("renders a Vue component", () => { | ||||||||||
| createComponent(); | ||||||||||
| expect(wrapper.exists()).toBe(true); | ||||||||||
|
Comment on lines
+38
to
+39
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer to have my setup methods to return the test subject:
Suggested change
|
||||||||||
| }); | ||||||||||
|
|
||||||||||
| describe("not logged in", () => { | ||||||||||
| beforeEach(() => createComponent()); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
|
||||||||||
| it("shows login link", () => { | ||||||||||
| const loginLink = wrapper.findComponent(RouterLinkStub); | ||||||||||
| expect(loginLink.exists()).toBe(true); | ||||||||||
| }); | ||||||||||
| it("links to /login page", () => { | ||||||||||
| const loginLink = wrapper.findComponent(RouterLinkStub); | ||||||||||
| expect(loginLink.props().to).toBe("/login"); | ||||||||||
| }); | ||||||||||
| it("does not show logout button", () => { | ||||||||||
| const logoutBtn = wrapper.find("#logoutBtn"); | ||||||||||
| expect(logoutBtn.exists()).toBe(false); | ||||||||||
| }); | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| describe("logged in", () => { | ||||||||||
| let logout = jest.fn(); | ||||||||||
|
|
||||||||||
| beforeEach(() => { | ||||||||||
| getters = { | ||||||||||
| loggedIn: () => true, | ||||||||||
| }; | ||||||||||
| actions = { | ||||||||||
| logout, | ||||||||||
| }; | ||||||||||
| createComponent(); | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| it("shows logout button", () => { | ||||||||||
| const logoutBtn = wrapper.find("#logoutBtn"); | ||||||||||
| expect(logoutBtn.exists()).toBe(true); | ||||||||||
| }); | ||||||||||
| it("calls logout when logout button is clicked", () => { | ||||||||||
| const logoutBtn = wrapper.find("#logoutBtn"); | ||||||||||
| logoutBtn.trigger("click"); | ||||||||||
| expect(logout.mock.calls.length).toBe(1); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
is the idiomatic way I think |
||||||||||
| }); | ||||||||||
| it("does not show login link", () => { | ||||||||||
| const loginLink = wrapper.findComponent(RouterLinkStub); | ||||||||||
| expect(loginLink.exists()).toBe(false); | ||||||||||
| }); | ||||||||||
| }); | ||||||||||
| }); | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||
| <template> | ||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||
| <template v-if="loggedIn"> | ||||||||||||||||||||||||||
| <button id="logoutBtn" @click="logout">Logout</button> | ||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||
| <template v-else> | ||||||||||||||||||||||||||
| <NuxtLink to="/login">Login</NuxtLink> | ||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
|
Comment on lines
+2
to
+9
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You could even remove the |
||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| <script> | ||||||||||||||||||||||||||
| import { mapGetters, mapActions } from "vuex"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export default { | ||||||||||||||||||||||||||
| computed: { | ||||||||||||||||||||||||||
| ...mapGetters(["loggedIn"]), | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| methods: { | ||||||||||||||||||||||||||
| ...mapActions(["logout"]), | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| </script> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| <style> | ||||||||||||||||||||||||||
| </style> | ||||||||||||||||||||||||||
|
Comment on lines
+25
to
+26
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!