vue3 콤보 api와 jest 유닛 테스트가 포함된 Laravel 때가 낀 예
117508 단어 vuetypescriptlaravelphp
서점
vue 구성 요소에 vuejs3 전단, 유형 스크립트, 단원 테스트를 포함하는 예시 laravel 프로그램을 만들 것입니다.
1. laravel 프로젝트 설립
새로운 도구로 laravel 프로젝트를 만듭니다.환경 파일
laravel new laravel-online-books && cd laravel-online-books
cp .env.example .env
에반 선생
APP_NAME="Online books"
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<YOUR_DB>
DB_USERNAME=<YOUR_DB_USER>
DB_PASSWORD=<YOUR_DB_PASSWORD>
...
composer를 실행하여 데이터베이스 설치 및 이전composer install
php artisan migrate
laravel/ui 비계와 비계 설정 uicomposer require Laravel/ui
php artisan ui bootstrap --auth
npm install && npm run dev
laravel starter 프로그램을 실행합니다php artisan key:generate
php artisan serve
2. 모형
artisan을 사용하여 이동을 통해 우리의 모형을 생성합니다.
php artisan make:model Book -m
테이블 마이그레이션 만들기// database/migrations/202x_xxx_create_books_table.php
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->integer('year');
$table->string('genre');
$table->string('author');
$table->string('publisher');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('books');
}
도서 모형.// app/models/book.php
class Book extends Model
{
use HasFactory;
protected $fillable = ['title' , 'year', 'genre',
'author','publisher'];
}
3. 데이터베이스에 테스트 데이터 심기
너는 이 부분을 뛰어넘을 수 있지만, 가장 좋은 것은 테스트 데이터가 시작되는 것이다.
php artisan make:seeder BookSeeder
// database/seeders/BookSeeder.php
public function run()
{
$authors = ['Terry A', 'Steven Price', 'John Smith'];
$genres = ['Fiction','Non-Fiction','Business','Horror'];
$publishers = ['Publisher A','Publisher B','Publisher C'];
for ($i = 0; $i <= 10; $i++) {
DB::table('books')->insert(
[
'title' => "Book title {$i}",
'year' => rand(1995, 2021),
'genre' => $genres[rand(0, count($genres)-1)],
'author' => $authors[rand(0, count($authors)-1)],
'publisher' => $publishers[rand(0,
count($publishers)-1)]
]);
}
}
응용 프로그램 데이터베이스 파종기에서 테스트 데이터 파종기를 호출하다// database/seeders/DatabaseSeeder.php
public function run()
{
$this->call([
BookSeeder::class
]);
}
마지막으로, 이전과 피드 데이터베이스.php artisan migrate --seed
3. 관제사와 노선
책 컨트롤러를 만듭니다. (이것은 우리의 API입니다.)
php artisan make:controller Api/BookController --resource --api --model=Book
자원을 창조하여 현상을 유지하다.php artisan make:resource BookResource
요청을 만들고 규칙 그룹을 업데이트합니다. 아래와 같습니다.php artisan make:request BookRequest
// app/Http/Requests/BookRequest.php
public function rules()
{
return [
'year' => ['required', 'integer'],
'title' => ['required', 'string'],
'genre' => ['required', 'string'],
'author' => ['required', 'string'],
'publisher' => ['required', 'string'],
];
}
현재 우리의 컨트롤러는 CRUD 조작을 지원한다.App/http/controllers/api/BookController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\BookRequest;
use App\Http\Resources\BookResource;
use App\Models\Book;
class BookController extends Controller
{
/**
* Get all books
**/
public function index()
{
return BookResource::collection(Book::all());
}
/**
* Store a book
**/
public function store(BookRequest $request)
{
$book = Book::create($request->validated());
return new BookResource($book);
}
/**
* Get one book
**/
public function show(Book $book)
{
return new BookResource($book);
}
/**
* Update a book
**/
public function update(BookRequest $request, Book $book)
{
$book->update($request->validated());
return new BookResource($book);
}
/**
* Delete a book
**/
public function destroy(Book $book)
{
$book->delete();
return response()->noContent();
}
}
마지막으로, 우리는 컨트롤러와 노선을 연결할 것이다.// App/routes/api.php
use App\Http\Controllers\Api\BookController;
// ...
Route::apiResource('books', BookController::class);
현재 서버가 실행될 때localhost:8000/api/books를 누르면 이 점을 테스트할 수 있습니다.4. vue3 프런트엔드 설정
노드 버전 12를 제 설정으로 사용하는 것을 권장합니다.
nvm use v12
vuejs3, vuejs3 로더, vue- 설치router@next타자 원고npm install --save vue@next vue-router@next vue-loader@next
npm install typescript ts-loader --save-dev
typescript를 설정합니다. 전단 모듈에서 typescript를 사용할 것입니다.tsconfig를 생성합니다.json
/* tsconfig.json */
{
"compilerOptions":
{
"module": "commonjs",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node"
}
}
패드를 추가합니다.typescript가 우리의 vue 파일을 이해할 수 있도록 d,ts 파일입니다.// resources/shims-vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
응용 프로그램에 vue loader 사용// webpack.mix.js
const mix = require('laravel-mix');
mix.ts('resources/js/app.ts', 'public/js')
.vue()
.sass('resources/sass/app.scss', 'public/css')
.sourceMaps();
이제 vue 공유기 루트를 설정합니다.라우터/인덱스를 만듭니다.ts
// resources/js/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import BookIndex from '../components/books/BookIndex.vue';
import BookShow from '../components/books/BookShow.vue';
const routes = [
{
path: '/home',
name: 'books.index',
component: BookIndex
},
{
path: '/books/:id/show',
name: 'books.show',
component: BookShow,
props: true
},
{ path: "/:pathMatch(.*)", component: { template: "Not found"} }
];
export default createRouter({
history: createWebHistory(),
routes
});
이제 구성 요소를 만듭니다.도서 색인.vue - 현재 우리는 그것을 비워 두고 설정에 중점을 둘 것이다
// resources/js/components/BookIndex.vue
<template>
<div class="container">
empty
</div>
</template>
도서 색인.vue - 현재 우리는 그것을 비워 두고 설정에 중점을 둘 것이다구성 요소 만들기
// resources/js/components/BookIndex.vue
<template>
<div class="container">
empty
</div>
</template>
vue 프로그램을 설치합니다. 확장을 확인하십시오.ts// resources/js/app.ts
require('./bootstrap');
import { createApp } from "vue";
import router from './router';
import BookIndex from './components/books/BookIndex.vue';
const app = createApp({
components: {
BookIndex,
},
}).use(router).mount('#app')
laravel 루트는 vue 공유기를 사용하여 URL 모드와 일치하는지/홈 페이지를 알려 줍니다.// routes/web.php
...
Route::view('/{any}', 'home')
->middleware(['auth'])
->where('any', '.*');
...
기본 블레이드 파일에 라우터 뷰 추가로그인한
...
<router-view />
...
우리 모두 잘 지내고 있으니 빨리 뛰어라npm run dev
그리고 신청서 다시 테스트해 봐.6.get 구성 요소 추가
우선, 우리는 조합할 수 있는 책을 추가할 것이다.우리는 여기에 모든api 논리를 저장할 것입니다.
자원/js/composables/books를 만듭니다.ts
// resources/js/composables/books.ts
import { ref } from 'vue'
import axios from "axios";
export default function useBooks() {
const books = ref([])
const book = ref([])
const getBooks = async () => {
const response = await axios.get('/api/books');
books.value = response.data.data;
}
const getBook = async (id: number) => {
let response = await axios.get('/api/books/' + id)
book.value = response.data.data;
}
return {
books,
book,
getBook,
getBooks
}
}
구성 요소 업데이트// resources/js/components/BookIndex.vue
<template>
<div class="container">
<div class="card" style="width: 18rem; float: left; margin: 5px" v-for="book in books" :key="book.id">
<router-link :to="{ name: 'books.show' , params: { id: book.id }}">
<div class="card-body">
<h5 class="card-title text-center">{{ book.title}}</h5>
<h6 class="card-subtitle mb-2 text-muted text-center">{{ book.year}}</h6>
<h6 class="card-subtitle mb-2 text-muted text-center">Author: {{ book.author}}</h6>
<h6 class="card-subtitle mb-2 text-muted text-center">Pblisher: {{ book.publisher}}</h6>
<h6 class="card-subtitle mb-2 text-muted text-center">Genre: {{ book.genre}}</h6>
</div>
</router-link>
</div>
</div>
</template>
<script lang='ts'>
import useBooks from '../../composables/books';
import { onMounted } from 'vue';
export default {
setup() {
const { books, getBooks } = useBooks()
onMounted(getBooks)
return {
books
}
}
}
</script>
// resources/js/components/BookShow.vue
<template>
<div class="container">
<div>
<h2 class="card-subtitle mb-2 text-muted">{{ book.title}}</h2>
<h6 class="card-subtitle mb-2 text-muted">year: {{ book.year}}</h6>
<h6 class="card-subtitle mb-2 text-muted">written by: {{ book.author}}</h6>
<h6 class="card-subtitle mb-2 text-muted">published by: {{ book.publisher}}</h6>
<h6 class="card-subtitle mb-2 text-muted">genre: {{ book.genre}}</h6>
</div>
<div class="row">
<div class="col-12 border">
<div class="card" style="width: 100%; margin: 10px; padding: 10px;" v-for="page in 10" :key="page">
<div class="card-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In varius facilisis dolor,
at porttitor nunc luctus sit amet. In tincidunt orci id mi finibus dapibus. Proin tempus,
lorem eu dapibus luctus, elit ante facilisis nulla, ac tristique augue justo eu turpis.
Donec eu enim a sem malesuada vulputate. In at placerat ex. Nullam tincidunt dolor et magna condimentum,
eu pulvinar lorem dictum. Phasellus venenatis rutrum imperdiet. Aenean eu massa lobortis, condimentum nunc sed,
molestie sem. Integer a interdum libero. Suspendisse mollis vehicula ligula a feugiat. Curabitur non odio sit amet mi
condimentum iaculis. Fusce sed tincidunt sem. Aenean porta viverra neque tristique ultricies.
</div>
</div>
</div>
</div>
</div>
</template>
<script lang='ts'>
import useBooks from '../../composables/books';
import { onMounted } from 'vue';
export default {
props: {
id: {
required: true,
type: String
}
},
setup(props: any) {
const { book, getBook } = useBooks()
onMounted(() => getBook(props.id))
return {
book
}
}
}
</script>
mix 재실행 및 응용 프로그램 테스트7.vue 구성 요소 테스트 추가
테스트를 실행하려면 다음과 같은 설정이 필요합니다.
npm install jest --save-dev
// jest.config.js
module.exports = {
testRegex: 'resources/assets/js/test/.*.spec.js$'
}
// package.json
scripts : {
...
"test": "jest"
}
vue jest 및 babel jest 추가:vue jest: @vue/vue3 jest for jest 27 및 vuejs3
npm install --save-dev @vue/vue3-jest babel-jest
vue-js-test-utils-3:npm install --save-dev @vue/test-utils@next
typescript로 테스트를 작성할 수 있도록 아래 내용을 추가합니다ts jest 및 @types\jest:
npm install --save-dev ts-jest
npm install --save-dev @types/jest
jest 구성 업데이트// jest.config.js
module.exports = {
"testEnvironment": "jsdom",
testRegex: 'resources/js/tests/.*.spec.ts$',
moduleFileExtensions: [
'js',
'json',
'vue',
'ts'
],
'transform': {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
'.*\\.(vue)$': '@vue/vue3-jest',
"^.+\\.tsx?$": "ts-jest"
},
}
구성 요소 테스트 작성//resources/js/tests/components/books/BookIndex.spec.ts
import { mount, shallowMount, flushPromises } from "@vue/test-utils";
import BookIndex from "../../../components/books/BookIndex.vue";
import router from "../../../router";
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
const fakeBooks = [{ "id": "1", "title": "book1", "subtitle": "hello1", "year": 1938}, { "id": "1", "title": "book1", "subtitle": "hello1", "year": 1938}, { "id": "1", "title": "book1", "subtitle": "hello1", "year": 1938}];
const fakeData = Promise.resolve({"data": {"data": fakeBooks}});
describe("BookIndex.vue", () => {
beforeEach(() => {
})
it("correctly mounts with correct data", async () => {
mockedAxios.get.mockReturnValueOnce(fakeData);
const wrapper = shallowMount(BookIndex, {
global: {
plugins: [router],
}
} as any);
expect(axios.get).toBeCalledWith("/api/books");
await flushPromises();
expect(wrapper.vm.books.length).toBe(3);
});
});
//resources/js/tests/components/books/BookShow.spec.ts
import { mount, shallowMount, flushPromises } from "@vue/test-utils";
import BookShow from "../../../components/books/BookShow.vue";
import router from "../../../router";
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
const testId = '3';
const fakeBook = { "id": "3", "title": "book1", "subtitle": "hello1", "year": 1938}
const fakeData = Promise.resolve({"data": fakeBook});
describe("BookShow.vue", () => {
beforeEach(() => {
})
it("correctly mounts with correct data", async () => {
mockedAxios.get.mockReturnValueOnce(fakeData);
const wrapper = shallowMount(BookShow, {
propsData: {
id: testId
},
global: {
plugins: [router],
}
} as any);
expect(axios.get).toBeCalledWith("/api/books/"+testId);
await flushPromises();
expect(wrapper.vm.book.id).toBe(testId);
});
});
더 많은 테스트를 작성할 수 있기 때문에 프로그램이 필요로 하는 모든 내용입니다.npm run test
8. 전체 CRUD(TDD 스타일)를 지원하도록 어플리케이션을 확장합니다.
어셈블리 BookCreate 생성
// resources/js/components/books/BookCreate.vue
<template>
<div class="container">
<form @submit.prevent="saveBook">
<div class="form-group">
<label>Title: </label>
<input type="text" class="form-control" placeholder="book title" v-model="form.title">
</div>
<div class="form-group">
<label>Year: </label>
<input type="text" class="form-control" placeholder="book year" v-model="form.year">
</div>
<div class="form-group">
<label>Author: </label>
<select class="form-control" v-model="form.author">
<option v-for="author in authors" :key="author">{{ author }}</option>
</select>
</div>
<div class="form-group">
<label>Publisher: </label>
<select class="form-control" v-model="form.publisher">
<option v-for="publisher in publishers" :key="publisher">{{ publisher }}</option>
</select>
</div>
<div class="form-group">
<label>Genre: </label>
<select class="form-control" v-model="form.genre">
<option v-for="genre in genres" :key="genre">{{ genre }}</option>
</select>
</div>
<div class="form-group"><br/>
<button :disabled="!submittable" type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</template>
<script lang='ts'>
import useBooks from '../../composables/books';
import { reactive, computed } from 'vue';
export default {
setup() {
const { errors, storeBook, authors, publishers, genres } = useBooks();
const form = reactive({
title: '',
author: '',
publisher: '',
genre: '',
year: null
})
const submittable = computed(() => {
return form.title !== '' && form.author !== ''
&& form.publisher !== '' && form.genre !== '' && form.year !== null;
});
const saveBook = async () => {
await storeBook({ ...form })
}
return {
form,
errors,
saveBook,
authors,
publishers,
genres,
submittable
}
}
}
</script>
이 새 구성 요소에 단추를 추가합니다.도서 색인에 추가하십시오.vue
<template>
<div class="container">
<div class="row">
+ <router-link :to="{ name: 'books.create' }" class="text-sm font-medium nav-link">
+ <button type="button" class="btn btn-primary">Add book</button>
+ </router-link>
</div>
<div class="card" style="width: 18rem; float: left; margin: 5px" v-for="book in books" :key="book.id">
.....
응용 프로그램에서 접근할 수 있도록 노선에 추가합니다.// resources/js/router/index.ts
//...
,
{
path: '/books/create',
name: 'books.create',
component: BookCreate,
},
//...
이제, 조합 가능한 책에create axios 호출을 추가합니다.vue 공유기를 사용하여 우리의 응용을 성공적인 색인 페이지로 바꿉니다.// resources/js/composables/books.ts
import { ref } from 'vue';
import axios from "axios";
import { useRouter } from 'vue-router'; // import vue router
export default function useBooks() {
const books = ref([])
const book = ref([])
const errors = ref('') // stores errors coming from our call so that we can display
const router = useRouter(); // instatiante vue-router
const authors = [ 'Terry A', 'Steven Price', 'John Smith', 'John Kennedy','Bryan Promise', 'Kyle David']; // fake authors options to select from when creating book
const publishers = [ 'Publisher A', 'Publisher B', 'Publisher C', 'Publisher D']; // fake publishers options to select from when creating book
const genres = ['Fiction', 'Non-Fiction', 'Business', 'Horror','Other']; // fake genres options to select from when creating book
const getBooks = async () => {
const response = await axios.get('/api/books');
books.value = response.data.data;
}
const getBook = async (id: number) => {
let response = await axios.get('/api/books/' + id)
book.value = response.data.data;
}
const storeBook = async (data: object) => {
errors.value = ''
try {
await axios.post('/api/books', data)
await router.push({name: 'books.index'}) // redirect app to index page on success
} catch (e: any) {
if (e.response.status === 422) {
errors.value = e.response.data.errors
}
}
}
return {
authors,
publishers,
genres,
errors,
books,
book,
getBook,
getBooks,
storeBook
}
}
구성 요소 테스트를 작성합니다. 모든 값이 채워졌는지 확인할 수 있는 제출 가능한 검사가 있습니다.그것은 하나의 계산 속성으로 실현되었다.
import { ..., computed } from 'vue';
...
const submittable = computed(() => {
return form.title !== '' && form.author !== ''
&& form.publisher !== '' && form.genre !== '' && form.year !== null;
});
어쨌든, 이것은 최소한 두 개의 테스트 용례를 작성할 수 있는 충분한 특성이다. 하나는 반드시false이고, 다른 하나는 반대이다.jest 테스트 용례:
it("allows submit when all values are set", async () => {
// set up test component
// fill out all the fields correctly
//assert to be submittable
expect(wrapper.vm.submittable).toBe(true);
});
it("disallows submit when all values are not set", async () => {
// set up test component
// fill out all the fields and leave out at least one
//assert to NOT be submittable
expect(wrapper.vm.submittable).toBe(false);
});
우리의 테스트// resources/js/tests/components/books/BookCreate.spec.ts
import { mount, shallowMount, flushPromises } from "@vue/test-utils";
import BookCreate from "../../../components/books/BookCreate.vue";
import router from "../../../router";
describe("BookIndex.vue", () => {
beforeEach(() => {
})
it("allows submit when all values are set", async () => {
const wrapper = shallowMount(BookCreate, {
global: {
plugins: [router],
}
} as any);
await wrapper.find('#title').setValue('test title');
await wrapper.find('#year').setValue(1994);
await wrapper.find('#publisher').setValue('test p');
await wrapper.find('#author').setValue('test a');
await wrapper.find('#genre').setValue('test g');
expect(wrapper.vm.submittable).toBe(true);
});
it("disallows submit when all values are set", async () => {
const wrapper = shallowMount(BookCreate, {
global: {
plugins: [router],
}
} as any);
expect(wrapper.vm.submittable).toBe(false);
});
});
이 때 추가: 편집 및: 삭제 기능은 쉬울 것입니다.하지만 우리 이거 계속 끝내자. <h6 class="card-subtitle mb-2 text-muted">published by: {{ book.publisher}}</h6>
<h6 class="card-subtitle mb-2 text-muted">genre: {{ book.genre}}</h6>
</div>
+ <div>
+ <router-link id="editBtn" :to="{ name: 'books.edit' , params: { id: `${book.id}` }}">Edit</router-link>
+ <a id="deleteBtn" @click="deleteBook(book)" href="#" role="button">Delete</a>
+ </div>
<div class="row">
<div class="col-12 border">
composable에 두 개의api 호출을 추가합니다// resources/js/composables/books.ts
/** Edit book **/
const updateBook = async (id: number) => {
errors.value = ''
try {
await axios.put('/api/books/' + id, book.value)
await router.push({name: 'books.index'})
} catch (e: any) {
if (e.response.status === 422) {
errors.value = e.response.data.errors
}
}
}
/** Delete book **/
const removeBook = async (id: number) => {
await axios.delete('/api/books/' + id);
await router.push({name: 'books.index'});
}
...
return {
...
updateBook,
removeBook
}
새 루트와 구성 요소를 알아보기 위해 vue 공유기를 업데이트합니다.// resources/js/router/index.ts
...
import BookEdit from '../components/books/BookEdit.vue';
...
,
{
path: '/books/:id/edit',
name: 'books.edit',
component: BookEdit,
props: true
},
...
새 BookEdit 어셈블리를 추가합니다.// resources/js/components/books/BookEdit.vue
<template>
<div class="container">
<form @submit.prevent="editBook">
<div class="form-group">
<label>Title: </label>
<input id="title" type="text" class="form-control" placeholder="book title" v-model="book.title">
</div>
<div class="form-group">
<label>Year: </label>
<input type="text" class="form-control" placeholder="book year" v-model="book.year" id="year">
</div>
<div class="form-group">
<label>Author: </label>
<select class="form-control" v-model="book.author" id="author">
<option v-for="author in authors" :key="author">{{ author }}</option>
</select>
</div>
<div class="form-group">
<label>Publisher: </label>
<select class="form-control" v-model="book.publisher" id="publisher">
<option v-for="publisher in publishers" :key="publisher">{{ publisher }}</option>
</select>
</div>
<div class="form-group">
<label>Genre: </label>
<select class="form-control" v-model="book.genre" id="genre">
<option v-for="genre in genres" :key="genre">{{ genre }}</option>
</select>
</div>
<div class="form-group"><br/>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</template>
<script lang='ts'>
import useBooks from '../../composables/books';
import { onMounted, computed } from 'vue';
export default {
props: {
id: {
required: true,
type: String
}
},
setup(props: any) {
const { errors, authors, publishers, genres, book, getBook, updateBook } = useBooks();
onMounted(() => getBook(props.id))
const editBook = async () => {
await updateBook(props.id);
}
return {
book,
errors,
editBook,
authors,
publishers,
genres
}
}
}
</script>
이것들을 위해 예시 테스트를 추가합시다BookEdit vue 어셈블리 테스트
// resources/js/tests/components/books/BookEdit.spec.ts
import { mount, shallowMount, flushPromises } from "@vue/test-utils";
import BookEdit from "../../../components/books/BookEdit.vue";
import router from "../../../router";
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
const testId = '3';
const fakeBook = { "id": "3", "title": "book1", "subtitle": "hello1", "year": 1938, 'author': 'A', 'publisher': 'A', 'genre': ''}
const fakeData = Promise.resolve({"data":{"data": fakeBook}});
describe("BookEdit.vue", () => {
beforeEach(() => {
})
it("correctly prepopulates form with correct existing data", async () => {
mockedAxios.get.mockReturnValueOnce(fakeData);
const wrapper = shallowMount(BookEdit, {
propsData: {
id: testId
},
global: {
plugins: [router],
}
} as any);
expect(axios.get).toBeCalledWith("/api/books/"+testId);
await flushPromises();
const titleInputField: HTMLInputElement = wrapper.find('#title').element as HTMLInputElement;
const yearInputField: HTMLInputElement = wrapper.find('#year').element as HTMLInputElement;
const prepopTitle = titleInputField.value;
const prepopYear = yearInputField.value;
expect(prepopTitle).toBe(fakeBook.title);
expect(prepopYear).toBe(`${fakeBook.year}`);
});
});
현재, delete는 자신의 구성 요소가 없기 때문에, 정확한 책 이름으로 delete를 눌렀을 때, delete 대화상자를 볼 수 있는지 테스트해 봅시다.우리들은 서적에 테스트 용례를 하나 추가할 것이다.규격.
// resources/js/tests/components/books/BookShow.spec.ts
...
it("shows user delete dialog on delete click.", async () => {
mockedAxios.get.mockReturnValueOnce(fakeData);
window.confirm = jest.fn(); // mock window.confirm implementation
const wrapper = shallowMount(BookShow, {
propsData: {
id: testId
},
global: {
plugins: [router],
}
} as any);
await flushPromises();
const button: HTMLElement = wrapper.find('#deleteBtn').element as HTMLElement;
button.click();
expect(window.confirm).toBeCalledWith(`delete ${fakeBook.title}?`)
});
...
초보자로서, 나는 이것이 충분하다고 생각한다. jest가jest 프로필에 다음 내용을 추가해서 테스트 범위율을 평가할 수 있다....
collectCoverage: true,
"collectCoverageFrom": [
"resources/js/**/*.{js,jsx}",
"resources/js/**/*.{ts,tsx}",
"resources/js/**/*.vue",
"!resources/js/tests/**/*.*",
"!**/node_modules/**",
"!**/vendor/**"
],
...
그리고 뛰다npm run test
마지막 작업 예:
https://github.com/LufunoMaphwanya/laraVue3-typescript-example
참조 자료:
https://laraveldaily.com/laravel-8-vue-3-crud-composition-api/
https://next.vue-test-utils.vuejs.org/guide/
Reference
이 문제에 관하여(vue3 콤보 api와 jest 유닛 테스트가 포함된 Laravel 때가 낀 예), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/lufunomaphwanya/laravel-crud-example-with-vue3-composition-api-jest-unit-tests-4kf1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)