Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions examples/TodoApp.spec.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,49 @@
/**
* This is the example app used in the documentation.
* If you want to run it, you will need to build the final bundle with
* yarn build. Then you can run this with `yarn test examples`
* pnpm build. Then you can run this with `pnpm test examples`
*/
import { mount } from '../dist/vue-test-utils.cjs.js'
import { test, expect } from 'vitest'
import { expect, describe, it } from 'vitest'

import TodoApp from './TodoApp.vue'

test('renders a todo', () => {
const wrapper = mount(TodoApp)
describe('Todo App', () => {
it('renders a todo', () => {
const wrapper = mount(TodoApp)

expect(wrapper.find('[data-test="todo"]').text()).toBe('Learn Vue.js 3')
})
expect(wrapper.find('[data-test="todo"]').text()).toBe('Learn Vue.js 3')
expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)
})

test('creates a todo', async () => {
const wrapper = mount(TodoApp)
it('creates a todo', async () => {
const wrapper = mount(TodoApp)

wrapper.find('[data-test="new-todo"]').element.value = 'New todo'
await wrapper.find('[data-test="form"]').trigger('submit')
await wrapper.find('[data-test="new-todo"]').setValue('New todo')
await wrapper.find('[data-test="form"]').trigger('submit')
expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)
})

expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)
})
it('should not creates duplicate todo', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creates -> create
duplicate -> duplicated

const wrapper = mount(TodoApp)

await wrapper.find('[data-test="new-todo"]').setValue('New todo')
await wrapper.find('[data-test="form"]').trigger('submit')
expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)

await wrapper.find('[data-test="form"]').trigger('submit')
expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)

await wrapper.find('[data-test="new-todo"]').setValue('New todo again')
await wrapper.find('[data-test="form"]').trigger('submit')
expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(3)
})

test('completes a todo', async () => {
const wrapper = mount(TodoApp)
it('completes a todo', async () => {
const wrapper = mount(TodoApp)

await wrapper.find('[data-test="todo-checkbox"]').setChecked()
await wrapper.find('[data-test="todo-checkbox"]').setChecked()

expect(wrapper.find('[data-test="todo"]').classes()).toContain('completed')
expect(wrapper.find('[data-test="todo"]').classes()).toContain('completed')
})
})
89 changes: 47 additions & 42 deletions examples/TodoApp.vue
Original file line number Diff line number Diff line change
@@ -1,52 +1,57 @@
<template>
<div>
<div
v-for="todo in todos"
:key="todo.id"
data-test="todo"
:class="[todo.completed ? 'completed' : '']"
<div>
<div
v-for="todo in todos"
:key="todo.id"
data-test="todo"
:class="getClass(todo.completed)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use: `:class="{ complete: todo.completed }" instead

Copy link
Author

@hdJerry hdJerry Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check it out. I just refactored what was there @cexbrayat
Thank you

>
{{ todo.text }}
<input
type="checkbox"
v-model="todo.completed"
data-test="todo-checkbox"
/>
</div>

<form data-test="form" @submit.prevent="createTodo">
<input data-test="new-todo" v-model="newTodo" />
</form>
{{ todo.text }}
<input
type="checkbox"
v-model="todo.completed"
data-test="todo-checkbox"
/>
</div>

<form data-test="form" @submit.prevent="createTodo">
<input data-test="new-todo" v-model="newTodo" />
</form>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref } from 'vue'
export default defineComponent({
name: 'TodoApp',
type TODO = {
id: number;
text: string;
completed: boolean;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use an interface named Todo here:

interface Todo {
  id: number;

data() {
return {
newTodo: '',
todos: [
{
id: 1,
text: 'Learn Vue.js 3',
completed: false
}
]
}
},
const newTodo = ref<string>('');
const todos = ref<TODO[]>([
{
id: 1,
text: 'Learn Vue.js 3',
completed: false
}
]);
methods: {
createTodo() {
this.todos.push({
id: 2,
text: this.newTodo,
completed: false
})
}
const createTodo = () =>{
const listLength = todos.value.length;
const lastItem = todos.value[listLength - 1];// get last todo item
const todoExist = todos.value.find(res => res.text.toLowerCase() === newTodo.value.toLowerCase());//check is todo already exists
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep the example as simple as it was and remove this

Copy link
Author

@hdJerry hdJerry Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the other is simple, but If we kept it the same, it wouldn’t act like a real TODO list — we’d end up with duplicate texts and IDs. So I added a small tweak to make the tests more realistic.
@cexbrayat

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's important to be realistic, a simple version is enough 👍

if(newTodo.value && !todoExist) {
const id = lastItem.id + 1;//increment the last item id by 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should a space before the comment, but it's weird that prettier did not catch it

todos.value.push({
id,
text: newTodo.value,
completed: false
});
}
})
};
const getClass = (completed: boolean) => [completed ? 'completed' : ''];
</script>