今天,当我们想制作一个水疗项目时,我们已经非常习惯,我们有三个选择:vue,angular或React;但是我们忘记了我们可以做到这一点,而没有任何这些框架迫使我们研究它们并以标志着我们实现业务目标的方式进行工作。
从头开始创建项目
要从头开始创建我们的水疗中心的项目,我们可以在本文中所述的WebPack中进行更多的手册进行操作,并集成了Jest:https://dev.to/raguilera82/montar-spa-de-cero-con-vanilla-y-jest-3odb
但是,今天我们还有另一种选择来创建我们的项目,并使用所有必要的过程,称为VITE,它也与称为Vitest的测试解决方案集成在一起,与Jest非常相似。
为此,我们只需要执行:
$> npm create vite@latest spa-app -- --template vanilla
$> cd spa-app
$> npm install
,对于Adir Vitest,我们只需要执行:
$> npm install -D vitest
以这种方式将有一个包裹。我们项目的最初状态:
{
"name": "spa-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest --coverage"
},
"devDependencies": {
"vite": "^4.3.2",
"vitest": "^0.31.1"
}
}
我们只有Vite和vitest的开发单位。现在,要启动一个示例的项目,我们可以使用命令来完成:
$> npm run dev
和http://localhost:5173 URL我们可以看到结果。
如果我们要使用应用程序的静态文件创建DIST文件夹,我们只需要执行:
$> npm run build
并在生产模式下对其进行测试,我们执行命令:
$> npm run preview
项目组织
不管创建我们的项目的方式以及我们要提供的功能,我们都将包括一个SRC文件夹,我们将在其中拥有项目的源代码,该文件中的一个唯一责任(由于可以在功能性妈妈的水平上进行增长的项目):
- 组件:它将存储调用用例的“ Web组件”。也就是说,知道我们的谎言的组成部分,并且可能与我们的应用状态有关系。
- Infra :您将存储与技术相关的文件,我们在其中支持自己制作应用程序。例如,在此文件夹中
- 模型:我们应用程序的域类将存储,并且将由“组件”文件夹的元素使用,并且作为建议将不与API中的内容相对应。<<<<<<<<<<<<<<<< /li>
- 页面:它将存储与我们水疗中心路由器相关的“ Web组件”。也就是说,它们将是我们可以从路由器航行的我们的页面。
- 息肉炎:您将存储允许访问API的课程,以与服务器互动。重要的是,此级别的类别对业务libic没有任何内容,与API联系并将信息传输到应用程序的其余部分很重要。
- 服务:它包含所有解决不同使用案例的横向功能的符号。
- ui :它包含我们仅用于应用程序接口的“ Web组件”,但没有任何类型的libic。也就是说,他们不调用用例,而是通过其他组件的属性或事件接收信息,并通过事件与其他组件进行通信。我们说它们是“愚蠢”的组件。
- 使用:它包含我们允许人们使用应用程序的动作。重要的是,每种使用案例都有唯一一个称为运行或执行的案例,即接收您执行并返回请求的信息所需的信息,所有这些信息都偏爱测试。
案例用例的实施
想象他们要求我们在应用程序中建立一个página,以连接到API(https://jsonplaceholder.typicode.com/)显示帖子列表,我们想显示的位置:postid,peasting,peading和content。
因此,我们已经可以创建具有以下内容的“ src/model/post.js”文件:
export class Post {
constructor({postId, heading, content}) {
this.postId = postId;
this.heading = heading;
this.content = content;
}
}
我们将从定义我们的用例的测试开始,这将使我们至少目前从视觉部分和与之连接的API中抽象。然后,我们创建“测试”文件夹和文件内部“ all-poses.usecase.spec.js”,我们开始思考哪些信息需要,并且信息必须返回使用案例,知道使用的情况只有我知道一切都是“执行”。
我们还知道,我们必须通过调用在Postman或浏览器本身中执行的URL https://jsonplaceholder.typicode.com/posts来恢复信息,并告诉我们100个记录将带有结构:USERID,ID,ID,标题,正文。因此,我们使用案例的结果应返回那100条记录,至少验证第一个位置与服务器返回的信息的第一个位置相吻合。
通过这种方式,我们在“ Test”中创建一个“固定装置”文件夹,并创建一个帖子文件。JON带有服务器返回的内容的Jon。
类似的东西:
import { describe, it } from 'vitest';
import postsServer from './fixtures/posts.json';
describe('All posts use case', () => {
it('should get all posts', () => {
const posts = AllPostsUseCase.execute();
expect(posts.length).toBe(postsServer.length);
expect(posts[0].postId).toBe(postsServer[0].id);
expect(posts[0].heading).toBe(postsServer[0].title);
expect(posts[0].content).toBe(postsServer[0].body);
})
})
显然,由于我们没有实施使用案例,因此未能进行测试,但是我们已经有一个测试可以响应我们业务线的需求。
现在,我们创建“ src/usecases/all-post.use.js”文件,该文件将拥有一个“执行”,最初将返回我们的固定装置,将我们的固定装置转换为模型等待应用程序:
import { Post } from '../model/post';
import postsServer from './../../test/fixtures/posts.json';
export class AllPostsUseCase {
static execute() {
return postsServer.map((postServer) => {
return new Post({
content: postServer.body,
heading: postServer.title,
postId: postServer.id
})
});
}
}
现在,我们使用npm run test
命令执行测试,并设法通过了测试。显然,我们没有与服务器连接,但是我们已经尝试过,模拟呼叫的模型的转换是正确的。
下一步是与服务器连接,为此,我们将创建文件“ src/repositis/posts.repositorry.js”,我们将在其中使用我们喜欢的基础架构实现对服务器的调用更重要的是,他们将想通过提取来做到这一点,我们将与Axios一起看到它,因为它与测试更兼容。
所以第一件事是安装依赖项。
$> npm install --save axios
,文件的内容将保持如下:
import axios from "axios";
export class PostsRepository {
async getAllPosts() {
return (await axios.get("https://jsonplaceholder.typicode.com/posts")).data;
}
}
现在,我们的用例不再需要固定装置,并且必须作为沥青:
import { Post } from '../model/post';
import { PostsRepository } from '../repositories/posts.repository';
export class AllPostsUseCase {
static async execute() {
const repository = new PostsRepository();
const postsServer = await repository.getAllPosts();
return postsServer.map((postServer) => {
return new Post({
content: postServer.body,
heading: postServer.title,
postId: postServer.id
})
});
}
}
,我们的测试现在是一个杂志:
import { describe, expect, it } from 'vitest';
import postsServer from './fixtures/posts.json';
import { AllPostsUseCase } from '../src/usecases/all-posts.usecase';
describe('All posts use case', () => {
it('should get all posts', async () => {
const posts = await AllPostsUseCase.execute();
expect(posts.length).toBe(postsServer.length);
expect(posts[0].postId).toBe(postsServer[0].id);
expect(posts[0].heading).toBe(postsServer[0].title);
expect(posts[0].content).toBe(postsServer[0].body);
})
})
如果我们再次执行kude0命令,我们会看到我们的测试继续通过绿色,但是...对于每次启动测试时,我们都会对服务器进行真实的调用,在大多数情况下,它是不是建议。这就是为什么我们必须嘲笑呼叫,为此,我们可以像开玩笑一样几乎平等地使用viest,一种方法可以是以下方法:
import { beforeEach, describe, expect, it, vi } from 'vitest';
import postsServer from './fixtures/posts.json';
import { AllPostsUseCase } from '../src/usecases/all-posts.usecase';
import { PostsRepository } from '../src/repositories/posts.repository';
vi.mock('../src/repositories/posts.repository');
describe('All posts use case', () => {
beforeEach(() => {
PostsRepository.mockClear();
})
it('should get all posts', async () => {
PostsRepository.mockImplementation(() => {
return {
getAllPosts: () => {
return postsServer;
}
}
})
const posts = await AllPostsUseCase.execute();
expect(posts.length).toBe(postsServer.length);
expect(posts[0].postId).toBe(postsServer[0].id);
expect(posts[0].heading).toBe(postsServer[0].title);
expect(posts[0].content).toBe(postsServer[0].body);
})
})
目前,我们正在对存储库进行模拟,我们给出了服务器通过调用所有“ getAllPosts”提供的答案。重要的是,在执行测试之前,我们将确保模拟,我们在之前进行此操作。
以这种方式,在等待从相应的页面调用时,用例的功能部分解决了,我们根本不必启动应用程序,这使得功能性的开发很大。
页面创建
要在水疗应用程序中创建página,我们需要拥有一个路由器,该路由器负责模拟应用程序页面之间的导航。
框架(Angular,React和Vue)已经为我们提供了他们自己的路由解决方案,但是我们可以回家这项技术,为了使我们保持香草或框架,我们将诉诸于库的库,以解决问题,以解决该问题是vaadin-router(https://github.com/vaadin/router),我们将使用以下命令安装:
$> npm install --save @vaadin/router
要使用路由器,我们将使用以下内容创建“ src/infra/router.js”文件:
import { Router } from "@vaadin/router";
import './pages/posts.page';
const outlet = document.querySelector("#app");
export const router = new Router(outlet);
router.setRoutes([
{ path: "/", component: "posts-page" },
{ path: "(.*)", redirect: "/" },
]);
不要忘记在我们应用程序的main.js文件中导入此文件,以这样的方式将其放置:
import "./src/infra/router";
并确保在index.html文件中具有“ app”标识符的元素,在我们的情况下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.js"></script>
</body>
</html>
现在,我们将创建我们在文件中导入的Página。为此,我们创建了“ SRC/pages/posts.page.js”文件,该文件将是一个本机网站,我们将用作其他组件的容器。该代码可能是以下内容,仅在Página中显示标题以及我们将通过使用RADH-POST的情况从服务器中恢复的帖子:
import "./../components/posts.component";
export class PostsPage extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<h1>Posts Page</h1>
<radh-posts></k-posts>
`;
}
}
customElements.define("posts-page", PostsPage);
然后,我们将实现组件“ radh-feosts”,这将是具有知道如何打电话的智能的组件,因此我们将在路由上创建它。 “为了实施,我们将依靠图书馆点亮,该图书馆高于标准的层
$> npm install --save lit
该组件的可能实现将是:
注意:我们使用的整个createrenderroot,以便屏幕读取器和SEO ARAE可以直接访问组件的整个内容。
import { LitElement, html } from "lit";
import { AllPostsUseCase } from "../usecases/all-posts.usecase";
import "./../ui/post.ui";
export class PostsComponent extends LitElement {
createRenderRoot() {
return this;
}
static properties = {
posts: {
type: Array,
},
};
async connectedCallback() {
super.connectedCallback();
this.posts = [];
this.posts = await AllPostsUseCase.execute();
console.log(this.posts);
}
render() {
return html`${this.posts.map(
(post) => html`<post-ui .post="${post}"></post-ui>`
)}`;
}
}
customElements.define("k-posts", PostsComponent);
可以看到此组件,它基于UI的另一个显示信息,因此我们使用此可能的实现创建了“ SRC/UI/POST.UI.JS”文件:
import { LitElement, html } from "lit";
export class PostUI extends LitElement {
createRenderRoot() {
return this;
}
static properties = {
post: {
type: Object,
},
};
render() {
return html`
<div>
<p>Post Id: ${this.post.postId}</p>
<p>Heading: ${this.post.heading}</p>
<p>Content: ${this.post.content}</p>
</div>
`;
}
}
customElements.define("post-ui", PostUI);
以这种方式,如果我们在使用npm run dev
启动应用程序时正确执行了不同的导入,则必须在屏幕上看到类似的内容:
结论
我希望本教程能反映出我们现在对使用水疗中心实现目标的框架所需的很少的需求。
无论如何,此实现与应涵盖路由和创建视觉组件的各个方面的框架不兼容,作为用例的实现和测试。