test work in progress
This commit is contained in:
21
src/components/EntryForm.test.ts
Normal file
21
src/components/EntryForm.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { mount } from '@vue/test-utils'
|
||||
import EntryForm from './EntryForm.vue'
|
||||
|
||||
describe('Entry Form tests', () => {
|
||||
|
||||
it('takes in values for name and title and displays them in the respected fields', () => {
|
||||
const name = faker.word.noun()
|
||||
const text = faker.lorem.paragraph()
|
||||
const component = mount(EntryForm, {
|
||||
props: {
|
||||
name, text, action: 'edit'
|
||||
}
|
||||
})
|
||||
|
||||
const nameField = component.find('input')
|
||||
const textField = component.find('textarea')
|
||||
console.log(nameField.element.classList, textField.text())
|
||||
})
|
||||
})
|
||||
@@ -1,14 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import * as z from 'zod'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Form, FormItem, FormLabel, FormField, FormControl, FormMessage, FormDescription } from '@/components/ui/form';
|
||||
import { Button } from './ui/button';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Entry } from '@/data/entries';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [value: CreateEntrySchema]
|
||||
submit: [value: CreateEntrySchema]
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -16,41 +15,38 @@ const props = defineProps<{
|
||||
inputEntry?: Entry | undefined
|
||||
}>()
|
||||
|
||||
const nameField = ref(props.inputEntry ? props.inputEntry.name : '')
|
||||
const textField = ref(props.inputEntry ? props.inputEntry.text : '')
|
||||
|
||||
const createEntryZodSchema = z.object({
|
||||
const createEntrySchema = z.object({
|
||||
name: z.string(),
|
||||
text: z.string().optional()
|
||||
})
|
||||
|
||||
export type CreateEntrySchema = z.infer<typeof createEntryZodSchema>
|
||||
export type CreateEntrySchema = z.infer<typeof createEntrySchema>
|
||||
|
||||
|
||||
function submit() {
|
||||
const result = createEntrySchema.safeParse({
|
||||
name: nameField.value,
|
||||
text: textField.value
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
emit('submit', result.data)
|
||||
}
|
||||
}
|
||||
|
||||
const createEntrySchema = toTypedSchema(createEntryZodSchema)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form :validation-schema="createEntrySchema" @submit="(val) => emit('submit', val as CreateEntrySchema)">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input placeholder="Name" v-bind="componentField" :model-value="inputEntry ? inputEntry.name : ''" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<FormField v-slot="{ componentField }" name="text">
|
||||
<FormItem>
|
||||
<FormLabel></FormLabel>
|
||||
<FormControl>
|
||||
<Textarea placeholder="Text" v-bind="componentField" :model-value="inputEntry ? inputEntry.text : ''" />
|
||||
</FormControl>
|
||||
<FormDescription />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<Button type="submit" class="w-full" v-if="props.action === 'create'">Create</Button>
|
||||
<Button type="submit" class="w-full" v-else>Edit</Button>
|
||||
</Form>
|
||||
<form class="flex gap-3 flex-col">
|
||||
<Input placeholder="Name" v-model:model-value="nameField" />
|
||||
<Textarea placeholder="Text" v-model:model-value="textField" />
|
||||
<Button class="w-full" v-if="props.action === 'create'" @click="submit()">Create</Button>
|
||||
<Button class="w-full" v-else @click="submit()">Edit</Button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
56
src/data/entries.test.ts
Normal file
56
src/data/entries.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { expect, it } from "vitest"
|
||||
import { describe } from "vitest"
|
||||
import { faker } from '@faker-js/faker'
|
||||
import { parseFromPossibleString } from "./entries"
|
||||
import moment from "moment"
|
||||
|
||||
|
||||
describe('function for managing entries data entity', () => {
|
||||
function generateList<E>(length: number, generate: () => E) {
|
||||
const arr: Array<E> = []
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
arr.push(generate());
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function generateListWithWrongDate() {
|
||||
return generateList(10, () => <any>{
|
||||
name: faker.word.noun(),
|
||||
text: faker.lorem.paragraph(),
|
||||
last_reset: faker.word.sample()
|
||||
})
|
||||
}
|
||||
|
||||
function generateListWithNoName() {
|
||||
return generateList(10, () => <any>{
|
||||
text: faker.lorem.paragraph(),
|
||||
last_reset: moment()
|
||||
})
|
||||
}
|
||||
|
||||
function generateListWithCorrectData() {
|
||||
return generateList(10, () => <any>{
|
||||
name: faker.word.noun(),
|
||||
text: faker.lorem.paragraph(),
|
||||
last_reset: moment()
|
||||
})
|
||||
}
|
||||
|
||||
it('fails to parse localstorage string because of wrong date', () => {
|
||||
const data = generateListWithWrongDate()
|
||||
expect(parseFromPossibleString(JSON.stringify(data)).length).toBe(0)
|
||||
})
|
||||
|
||||
it('fails to parse localstorage string because no name was parsed', () => {
|
||||
const data = generateListWithNoName()
|
||||
expect(parseFromPossibleString(JSON.stringify(data)).length).toBe(0)
|
||||
})
|
||||
|
||||
it('succeeds to parse localstorage string witht he correct data', () => {
|
||||
const data = generateListWithCorrectData()
|
||||
expect(parseFromPossibleString(JSON.stringify(data)).length).toBe(10)
|
||||
})
|
||||
})
|
||||
@@ -1,39 +1,46 @@
|
||||
import moment, { Moment } from "moment";
|
||||
import { Ref, ref } from "vue";
|
||||
|
||||
const localStorageKey = 'entries'
|
||||
export const localStorageKey = 'entries'
|
||||
|
||||
export function getDifferenceToToday(date: Moment) {
|
||||
return Math.abs(date.diff(moment(), 'days'))
|
||||
return Math.abs(date.diff(moment(), 'days'))
|
||||
}
|
||||
|
||||
export const entries: Ref<Entry[]> = ref(parseFromPossibleString(localStorage.getItem(localStorageKey)))
|
||||
|
||||
export interface Entry {
|
||||
name: string
|
||||
text: string | undefined
|
||||
last_reset: Moment
|
||||
name: string
|
||||
text: string | undefined
|
||||
last_reset: Moment
|
||||
}
|
||||
|
||||
export function parseFromPossibleString(input: string | null): Entry[] {
|
||||
if (input === null) {
|
||||
return []
|
||||
}
|
||||
if (input === null) {
|
||||
return []
|
||||
}
|
||||
|
||||
const entries: Entry[] = []
|
||||
const rawObjects: any[] = JSON.parse(input)
|
||||
const entries: Entry[] = []
|
||||
const rawObjects: any[] = JSON.parse(input)
|
||||
|
||||
for (const rawObject of rawObjects) {
|
||||
const { name, text, last_reset } = rawObject
|
||||
for (const rawObject of rawObjects) {
|
||||
const { name, text, last_reset } = rawObject
|
||||
const date = parseDate(last_reset)
|
||||
|
||||
if (name && last_reset) {
|
||||
entries.push({ name, text, last_reset: moment(last_reset) })
|
||||
}
|
||||
}
|
||||
if (date && name) {
|
||||
entries.push({ name, text, last_reset: moment(last_reset) })
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
export function save() {
|
||||
localStorage.setItem(localStorageKey, JSON.stringify(entries.value))
|
||||
export function parseDate(dateString: string) {
|
||||
const date = moment(dateString)
|
||||
if (!date.isValid()) {
|
||||
return undefined
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
export function save(entries: Entry[]) {
|
||||
localStorage.setItem(localStorageKey, JSON.stringify(entries))
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Card, CardTitle, CardDescription } from '@/components/ui/card';
|
||||
import { entries, getDifferenceToToday, save } from '@/data/entries';
|
||||
import { entries } from '@/state/entry';
|
||||
import { getDifferenceToToday, save } from '@/data/entries';
|
||||
import { ArrowBigLeft, MenuIcon, TrashIcon } from 'lucide-vue-next';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -40,7 +41,7 @@ function deleteEntry() {
|
||||
}
|
||||
|
||||
entries.value.splice(index, 1)
|
||||
save()
|
||||
save(entries.value)
|
||||
router.back()
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ function resetDate() {
|
||||
|
||||
entry.value.last_reset = moment()
|
||||
confirmDialogState.value = false
|
||||
save()
|
||||
save(entries.value)
|
||||
}
|
||||
|
||||
function editEntry(val: CreateEntrySchema) {
|
||||
@@ -65,7 +66,7 @@ function editEntry(val: CreateEntrySchema) {
|
||||
entry.value.name = val.name
|
||||
entry.value.text = val.text
|
||||
editEntryDialog.value = false
|
||||
save()
|
||||
save(entries.value)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Plus } from 'lucide-vue-next';
|
||||
import { entries, save } from '@/data/entries';
|
||||
import { entries } from '@/state/entry'
|
||||
import { save } from '@/data/entries';
|
||||
import { Drawer, DrawerHeader, DrawerTitle, DrawerContent } from '@/components/ui/drawer';
|
||||
import { Dialog, DialogHeader, DialogTitle, DialogContent } from '@/components/ui/dialog';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -36,7 +37,7 @@ async function createEntry(value: CreateEntrySchema) {
|
||||
? value.text : undefined
|
||||
})
|
||||
|
||||
save()
|
||||
save(entries.value)
|
||||
createDrawerState.value = false
|
||||
}
|
||||
|
||||
|
||||
1
src/shims-vue.d.ts
vendored
Normal file
1
src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module '*.vue'
|
||||
4
src/state/entry.ts
Normal file
4
src/state/entry.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Entry, localStorageKey, parseFromPossibleString } from "@/data/entries";
|
||||
import { Ref, ref } from "vue";
|
||||
|
||||
export const entries: Ref<Entry[]> = ref(parseFromPossibleString(localStorage.getItem(localStorageKey)))
|
||||
Reference in New Issue
Block a user