当前位置: 首页 > news >正文

凡科建设网站怎么保存广州网站的建设

凡科建设网站怎么保存,广州网站的建设,互联网络推广,抖音关键词seo系统Jest Jest 概述 Jest是一个领先的JavaScript测试框架#xff0c;特别适用于React和Node.js环境。由Facebook开发#xff0c;它以简单的配置、高效的性能和易用性而闻名。Jest支持多种类型的测试#xff0c;包括单元测试、集成测试和快照测试#xff0c;后者用于捕获组件或…Jest Jest 概述 Jest是一个领先的JavaScript测试框架特别适用于React和Node.js环境。由Facebook开发它以简单的配置、高效的性能和易用性而闻名。Jest支持多种类型的测试包括单元测试、集成测试和快照测试后者用于捕获组件或数据结构的状态以便于后续的比较和验证。Jest自动化模拟依赖项和异步代码测试提高了测试的可靠性和灵活性。其并行测试执行机制显著加快了测试过程而交互式监视模式则在开发过程中提供即时反馈。此外Jest还提供内置的代码覆盖率工具帮助开发者优化测试范围。因其强大的功能和广泛的社区支持Jest成为现代JavaScript项目中不可或缺的测试工具。 Jest 环境配置 安装包 1、jest这是 Jest 测试框架本身。 2、types/jest这是 Jest 的 TypeScript 类型定义用于在使用 TypeScript 编写测试时提供类型检查和自动完成功能。 3、babel-jest这是用于将 Jest 集成到使用 Babel 的项目中的插件。它允许 Jest 处理通过 Babel 转换的代码。 4、ts-jest这是一个 Jest 转换器用于处理 TypeScript 文件。它基本上允许 Jest 理解和运行 TypeScript 测试代码。 5、jest-transform-stub这个插件用于处理非 JavaScript 资源如 CSS 和图片的导入这在 Jest 测试中通常会被忽略或需要特殊处理。 npm install --save-dev jest types/jest babel-jest ts-jest jest-transform-stub6、testing-library/jest-dom提供一套针对 DOM 元素的 Jest 断言非常适用于在测试 React 组件时使用。 7、testing-library/react用于测试 React 组件它提供了渲染组件、查询 DOM 元素以及与组件交互的工具。 8、testing-library/user-event这个库用于模拟用户事件如点击、输入等可用于更逼真地测试用户交互。 npm install --save-dev testing-library/jest-dom testing-library/react testing-library/user-event9、eslint-plugin-jest这是一个 ESLint 插件提供针对 Jest 测试的特定规则有助于保持测试代码的质量和一致性。 10、react-test-renderer: 这是一个用于渲染 React 组件为 JavaScript 对象的库常用于 Jest 的快照测试。它可以在不需要 DOM 环境的情况下测试 React 组件的输出这对于在 Node 环境下运行的 Jest 测试非常有用。 npm install --save-dev eslint-plugin-jest react-test-rendererpackage.json 1、基本的运行测试用例配置npm test即可运行 --watchAll这个参数告诉 Jest 进入 “watch” 模式。在这个模式下 Jest 会监视项目中的文件变化。当修改并保存了代码文件包括测试文件和被测试的源代码文件时 Jest 会自动重新运行相关的测试。 --watchAll 与 --watch 不同之处在于--watchAll 会在初次运行时执行所有测试而 --watch 只在检测到文件更改时运行相关测试。 test: jest --watchAll,2、运行某个文件夹下的所有测试文件src/tests代表文件夹路径 test:folder: jest --watchAll --testPathPatternsrc/tests,3、单独运行某个测试文件src/renderer/login/loginApi.test.tsx代表需要测试的文件路径 test:single: jest --watchAll jest --findRelatedTests src/renderer/login/loginApi.test.tsx,常见的 Jest 命令行操作 1、f 只会跑测试未通过的用例再次点击 f 会取消当前模式。 2、o 只监听已改变的文件如果存在多个测试文件可以开启会与当前 git 仓库中的提交进行比较需要使用 git 来监听哪个文件修改了也可以将 --watchAll 改为 --watch 只会运行修改的文件。 3、a 运行所有测试如果在 watch 模式中使用了 f 或 o 使用 a 可以恢复运行所有测试。 4、u 用于更新 Jest 快照测试中的快照。如果更改了渲染组件的输出可以使用此命令更新快照。 5、w 显示 Jest watch 模式中的所有可用命令和选项的列表。 6、q 退出 Jest 的 watch 模式。 7、i 只会运行之前运行失败的测试文件但提供更交互式的体验。 .babelrc 当使用 Jest 测试一个使用 Babel 编译的项目时Jest 会通过这些配置来正确处理和理解 JavaScript 代码。 {// 设置插件集合presets: [// 使用当前插件可以进行转换// 数组的第二项为插件的配置项[babel/preset-env,{// 根据 node 的版本号来结合插件对代码进行转换targets: {node: current}}]] }setupTests.js 该文件设置测试环境中的全局对象和模拟mock某些模块在本项目中针对 Electron 和 Node.js 的相关模块进行模拟以便在不依赖实际 Electron 或浏览器环境的情况下测试特定的功能。 /* eslint-disable no-undef */ const electronMock require(./__Mock__/electronMock)global.window.require jest.fn(moduleName {if (moduleName electron) {return electronMock}if (moduleName electron/remote) {return {require: jest.fn(module {// 模拟 Node.js 模块如 fsif (module fs) {return {} // 返回 fs 的模拟实现}// 其他模块模拟...}),}} }) global.window.matchMedia global.window.matchMedia ||function () {return {matches: false,addListener: function () {},removeListener: function () {},}}jest.config.ts jest.config.ts 是一个使用 TypeScript 编写的 Jest 配置文件。可以使用npx jest --init初始化命令来生成一个基本的配置文件。 export default {// 自动清除 mock 调用和实例clearMocks: true,// 开启代码覆盖率收集collectCoverage: true,// 代码测试覆盖率通过分析那些文件生成的!代表不要分析collectCoverageFrom: [**/*.{ts,js,tsx}, !**/node_modules/**, !**/vendor/**],// 代码覆盖率报告的输出目录coverageDirectory: coverage,// 代码覆盖率的收集器这里使用 V8 引擎coverageProvider: v8,// 代码覆盖率报告的格式coverageReporters: [text-summary,lcov,],globals: {ts-jest: {// 关闭 ts-jest 的诊断信息diagnostics: false,},},// 引入模块时进行自动查找模块类型逐个匹配moduleFileExtensions: [js, jsx, ts, tsx, json, node],// 模块名字使用哪种工具进行映射moduleNameMapper: {^/(.*)$: rootDir/src/$1, //将 / 映射到 src/ 目录\\.(css|less)$: jest-transform-stub,^localTypes$: rootDir/src/types.ts,^localUtils$: rootDir/src/utils/index.ts,^localConst$: rootDir/src/utils/constants.ts,^Assets/(.*)$: rootDir/assets/$1,},preset: ts-jest,rootDir: undefined,// 检测从哪个目录开始rootDir 代表根目录roots: [rootDir/src],// 在运行测试之前执行的文件设置测试环境setupFilesAfterEnv: [./setupTests.js],// 测试运行的环境会模拟 domtestEnvironment: jsdom,// 哪些文件会被认为测试文件testMatch: [// src 下的所有 __tests__ 文件夹中的所有的 js jsx ts tsx 后缀的文件都会被认为是测试文件rootDir/src/**/__tests__/**/*.{js,jsx,ts,tsx},// scr 下的所有以 .test/spec.js/jsx/ts/tsx 后缀的文件都会被认为是测试文件rootDir/src/**/*.{spec,test}.{js,jsx,ts,tsx},],// 测试时忽略的路径testPathIgnorePatterns: [\\\\node_modules\\\\],// 测试文件中引用一下后缀结尾的文件会使用对应的处理方式transform: {^.\\.(t|j)s$: ts-jest,\\.svg$: rootDir/__Mock__/svgTransform.js,}, }__Mock__文件夹 文件夹用于存放模拟mock模块 自动模拟当调用jest.mock(moduleName)时Jest会查找__mocks__文件夹中名为 moduleName 的文件并自动使用该文件中的模拟实现。这意味着不需要在每个测试文件中手动设置模拟。 第三方模块模拟这个机制不仅适用于自定义模块也适用于第三方模块。例如正在使用一个发送 fetch 请求的库可以在 __mocks__文件夹中创建一个模拟以避免在测试中发出真实的网络请求。 Mock Mock fetch 或其他 HTTP 请求库的调用 待补充 Mock 函数 jest.fn()Mock 第三方模块 待补充 全局函数 describe 和 it describe 用于将测试分组而 it 用于定义单个具体的测试用例。可以在 describe 块中放置多个 it 测试用例也可以嵌套其他 describe 块以创建更详细的测试结构。 // 用于创建一个测试套件将一组功能或逻辑相关的测试用例组织在一起 describe(测试输入框的校验规则, () {// it 的第一个参数是一个字符串描述了测试用例应该做什么有助于代码的可读性和测试结果的理解it(输入正常, async () {// ...});it(必填, async () {// ...});it(仅支持汉字、字母、数字和-_%., async () {// ...})it(以数字、字母或汉字开头, async () {// ...})it(限长, async () {// ...}) });断言 expect 用于验证代码的行为是否符合预期。 expect 函数接受一个参数———想要测试的值。然后expect 返回一个“期望对象”这个对象提供了一系列“匹配器”matcher方法用于声明对这个值的期望。 describe(测试输入框的校验规则, () {it(必填, async () {// ...expect(message).toBeInTheDocument()})it(仅支持汉字、字母、数字和-_%., async () {// ...expect(message).toBeInTheDocument()})it(以数字、字母或汉字开头, async () {// ...expect(message).toBeInTheDocument()})it(限长, async () {// ...expect(message).toBeInTheDocument()})it(输入正常, async () {// ...await waitFor(() {expect(input.className).toMatch(ant-input-status-success)})}) })匹配器 toBe 期待是否与匹配器中的值相等相当于object.is toMatch 匹配当前字符串中是否含有这个值支持正则 toContain 用于检查数组或字符串是否包含特定项或子串 toBeInTheDocument 判断某个元素是否在文档中即是否已被渲染到 DOM 上 toHaveProperty 用于检查对象是否具有特定属性可以选择性地检查属性值 toEqual 是“相等”不是“相同”相当于 toBeFalsy 和 toBeTruthy 检查一个值是否为假或真 toBeNull 专门用来检查一个值是否为 null toBeDefined 和 toBeUndefined 这些断言用于检查变量是否已定义或未定义 toThrow 用于检查函数是否抛出错误 not用于对断言取反 snapshot 快照 会在当前测试文件位于的文件夹下生成一个__snapshots__文件夹该文件夹下会生成扩展名为 .snap 文件文件会保存代码运行的结果如渲染的组件树、数据结构等。 toMatchSnapshot 方法接受一个参数是快照名称字符串类型。 expect(container).toMatchSnapshot(必填)一定要是 container 不能是 screen 用 screen 不会保存 DOM 结构 优势 自动化比较Jest 自动比较快照减少了手动检查输出的需要。 简化复杂结构的测试对于复杂的对象或大型UI组件编写传统测试断言可能很困难。快照测试可以轻松捕获整个结构。 文档化变化快照文件也可以作为代码行为的一种文档让开发者和审阅者理解代码更改的影响。 快照更新当代码发生更改导致快照不再匹配时可以使用 jest --updateSnapshot 命令或jest -u命令来更新快照。 测试用例覆盖率报告 会在主文件夹下生成一个名为 coverage 的文件夹打开里面的 html 就可以看到各个文件的覆盖率通常包含以下几种主要的覆盖率类型 行覆盖率Line Coverage测量有多少行代码被测试用例执行过。如果一行代码在测试中至少被执行一次那么这一行就被认为是覆盖了的。 函数覆盖率Function Coverage测量有多少个函数或方法被测试用例调用过。即使函数内的某些行没有被执行只要函数被调用它就被认为是覆盖了的。 分支覆盖率Branch Coverage测量代码中的每个if语句、循环、switch语句等的每个分支是否都被执行过。这是检查条件语句的完整性的重要指标。 语句覆盖率Statement Coverage测量有多少个独立语句被测试执行过。这与行覆盖率类似但关注的是语句的执行。 React Testing Library render 渲染 React 组件到一个虚拟的 DOM 环境中以便进行测试。 render 函数接受一个 React 组件作为参数并返回一个包含多个属性和方法的对象例如 container 和 debug 。 container 可以调用各类查询函数在渲染的组件中查找元素 debug 可以打印出 baseElement 的内部HTML用于调试。 describe(测试输入框的校验规则, () {it(输入正常, async () {const Com Index /const container render(Com)container.debug()}) })screen 在使用 React Testing Library 进行测试时通常会先用 render 函数渲染组件然后用 screen 查询和操作元素。screen 对象可以在测试文件中全局访问无需在每个测试中单独导入或创建。 describe(测试输入框的校验规则, () {it(输入正常, async () {render(Index /)screen.debug()}) })查询函数 React Testing Library 提供了一系列的查询函数用于在 Jest 测试中找到 DOM 节点。 getBy… getByText: 根据文本内容查找元素。 getByLabelText: 根据关联的 label 文本查找 input, select, 或 textarea 元素。 getByPlaceholderText: 根据占位符文本查找输入框。 getByAltText: 根据图片的 alt 属性文本查找图片元素。 getByTitle: 根据 title 属性查找元素。 getByRole: 根据 ARIA 角色查找元素。 getByTestId: 根据 data-testid 属性查找元素。 queryBy… queryBy...函数的行为类似于 getBy... 函数但当查询的元素不存在时它们返回 null 而不是抛出错误。这对于断言某个元素不在页面上非常有用。 findBy… findBy...函数是 getBy... 函数的异步版本。它们返回一个 Promise适用于等待异步操作完成后元素出现在 DOM 中的情况。 …AllBy…, queryAllBy…, findAllBy… 这些函数的行为类似于 getBy..., queryBy..., 和 findBy...但用于返回多个匹配的元素。如果没有找到匹配的元素getAllBy... 和 findAllBy... 会抛出错误而 queryAllBy... 返回一个空数组。 总结 getBy... 函数用于当确定元素存在时。如果元素不存在测试将失败。 queryBy... 函数用于当元素可能不存在需要处理这种情况时。 findBy... 函数用于处理异步逻辑当需要等待元素出现时。 ...AllBy... 函数用于处理有多个匹配元素的情况。 // findByText参数必须是完整的文本如果是子字符串需要加上{exact: false} // findByText不管前缀是screen还是container都可以成功 describe(测试输入框的校验规则, () {it(仅支持汉字、字母、数字和-_%., async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)await userEvent.type(input, )const messages await container.findByText(溶剂名称仅支持汉字、字母、数字和-_%.)}) }) describe(测试输入框的校验规则, () {it(仅支持汉字、字母、数字和-_%., async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)await userEvent.type(input, )const messages await screen.findByText(仅支持汉字、字母、数字和-_%., {exact: false})}) })waitFor 用于处理异步操作和元素的异步更新。waitFor 常与异步查询函数如 findBy…结合使用用于处理组件状态更新或数据加载。 describe(测试输入框的校验规则, () {it(输入正常, async () {const container render(Index /)screen.debug()const input await screen.findByRole(textbox)await waitFor(() {expect(screen.getByText(必填, { exact: false })).toBeInTheDocument()})}) })fireEvent 和 userEvent Jest 提供fireEvent和userEvent模拟用户操作。 fireEvent直接同步触发 DOM 事件。当调用 fireEvent 的任何方法时如 fireEvent.click它会立即生成对应的 DOM 事件并同步地传递给目标元素。因此fireEvent 方法调用后不会返回 Promise也不涉及任何异步操作所以通常不需要使用 await 关键字。 userEvent旨在更贴近用户的实际操作因此它经常涉及到一系列复杂的、可能是异步的事件。例如当用户在输入框中输入文字时这不仅仅是一个简单的同步操作。它包含了一系列的键盘和输入事件这些事件可能会触发各种事件处理器这些处理器本身可能是异步的。 1、fireEvent来自testing-library/reactuserEvent来自testing-library/user-event 2、fireEvent的清空 Input 输入框操作为fireEvent.change(input, {target: {value: }})userEvent的清空 Input 输入框操作为userEvent.type(input, {backspace}) 3、fireEvent前不需要添加awaituserEvent需要。 总结如果需要模拟简单的事件并需要完全控制这些事件的属性fireEvent 是个好选择。而如果需要模拟更复杂或更接近真实用户行为的交互userEvent 则更合适。 describe(测试输入框的校验规则, () {it(仅支持汉字、字母、数字和-_%., async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)fireEvent.change(input, {target: {value: }})}) }) describe(测试输入框的校验规则, () {it(仅支持汉字、字母、数字和-_%., async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)await userEvent.type(input, )}) })Jest 测试案例 测试 Input 输入框的校验规则 当前 Input 输入框的校验规则 1必填 2限长100 3仅支持汉字、字母、数字和-_%. 4必须以数字、字母或汉字开头 const nameRules ({label,max 10,required true, }: {label: stringmax?: numberrequired?: boolean }): Rule[] [{ required, message: ${label}必填 },{ type: string, max, message: ${label}限长${max} },{pattern: /^([a-zA-Z0-9\u4E00-\u9FA5_.%-])*$/g,message: ${label}仅支持汉字、字母、数字和-_%.,},{pattern: /^([0-9|a-zA-Z0-9|\u4E00-\u9FA5])/g,message: ${label}以数字、字母或汉字开头,},]因被测试组件的复杂程度不同测试同一个功能所用的 API 也不同 1被测试功能组件的简单版 该组件只有基本的页面布局和nameRules校验规则 /* eslint-disable react-hooks/rules-of-hooks */ import { nameRules } from /utils/constants import { Form, Input } from antdconst myInput () {return (FormForm.ItemlabelUsernamenameusername// 校验规则rules{nameRules({label: 名称,required: true,})}Input //Form.Item/Form) } export default myInput在测试较简单的组件时模拟用户操作可以使用fireEvent.change()断言也无需包裹在waitFor中便可同步执行。 /* eslint-disable no-undef */ import { fireEvent, render, screen, waitFor } from testing-library/react import Index from ./index import testing-library/jest-domdescribe(测试输入框的校验规则, () {it(必填, async () {// 渲染组件const Com Index /const container render(Com)// findByRole不管前缀是screen还是container都可以成功const input await screen.findByRole(textbox)// 在 input 输入框中输入1fireEvent.change(input, { target: { value: 1 } })// 清空 inputfireEvent.change(input, { target: { value: } })// findByText参数必须是完整的文本如果是子字符串需要加上{exact: false}expect(await container.findByText(必填, { exact: false })).toBeInTheDocument()})it(仅支持汉字、字母、数字和-_%., async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)fireEvent.change(input, { target: { value: } })expect(await container.findByText(仅支持汉字、字母、数字和-_%., { exact: false })).toBeInTheDocument()})it(以数字、字母或汉字开头, async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)fireEvent.change(input, { target: { value: - } })expect(await container.findByText(以数字、字母或汉字开头, { exact: false })).toBeInTheDocument()})it(限长, async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)fireEvent.change(input, { target: { value: a.repeat(101) } })expect(await container.findByText(限长, { exact: false })).toBeInTheDocument()})it(输入正常, async () {const Com Index /const container render(Com)const input await screen.findByRole(textbox)fireEvent.change(input, { target: { value: 1 } })await waitFor(() {expect(input.className).toMatch(ant-input-status-success)})}) })2被测试功能组件的复杂版 该组件是个集合组件功能比较复杂被测试的输入框只是其中一小部分内容。 因为组件存在 fetch 接口的请求但是 jest 测试不会运行真实的 fetch 接口所以需要 mock 数据在本组件中通过在catch中给定初始数据。 在复杂环境下render组件时需要 mock 渲染组件所需的各项参数在本组件中id值是直接给定一个存在的 id onCancel方法 mock 一个空函数Dn初始化数据。 此时模拟用户操作须使用await userEvent.type()断言外须包裹await waitFor(() {})。 /* eslint-disable no-undef */ import { fireEvent, render, screen, waitFor } from testing-library/react import ComplexIndex from ./ComplexIndex import testing-library/jest-dom import userEvent from testing-library/user-eventdescribe(测试输入框的校验规则, () {const onCancelMock jest.fn()it(必填, async () {// 渲染组件render(ComplexIndexid93eonCancel{onCancelMock}Dn{{dn1: 1,dn2: ,}}/)const input await screen.findByRole(textbox)// 在 input 输入框中输入“正常输入”await userEvent.type(input, 1)// 清空 inputawait userEvent.type(input, {backspace})// 异步等待断言执行await waitFor(() {expect(screen.getByText(必填, { exact: false })).toBeInTheDocument()})})it(正常输入, async () {render(ComplexIndexid93eonCancel{onCancelMock}Dn{{dn1: 1,dn2: ,}}/)const input await screen.findByRole(textbox)await userEvent.type(input, 正常输入)await waitFor(() {expect(input.className).toMatch(ant-input-status-success)})})it(限长, async () {render(ComplexIndexid93eonCancel{onCancelMock}Dn{{dn1: 1,dn2: ,}}/)const input await screen.findByRole(textbox)await userEvent.type(input, a.repeat(101))await waitFor(() {expect(screen.getByText(限长, { exact: false })).toBeInTheDocument()})})it(仅支持汉字、字母、数字和-_%., async () {render(ComplexIndexid93eonCancel{onCancelMock}Dn{{dn1: 1,dn2: ,}}/)const input await screen.findByRole(textbox)await userEvent.type(input, )await waitFor(() {expect(screen.getByText(仅支持汉字、字母、数字和-_%., { exact: false })).toBeInTheDocument()})})it(以数字、字母或汉字开头, async () {render(ComplexIndexid93eonCancel{onCancelMock}Dn{{dn1: 1,dn2: ,}}/)const input await screen.findByRole(textbox)await userEvent.type(input, -)await waitFor(() {expect(screen.getByText(以数字、字母或汉字开头, { exact: false })).toBeInTheDocument()})}) })3获取原始 DOM 内容进行测试 Input 标签有aria-describedby属性该属性的属性值是某个div的id该div下的div包含所有类型的报错字样。 /* eslint-disable no-undef */ import { fireEvent, render, screen } from testing-library/react import Index from ./index import testing-library/jest-dom import userEvent from testing-library/user-eventdescribe(测试输入框的校验规则, () {it(仅支持汉字、字母、数字和-_%., async () {// 渲染被测组件const Com Index /const container render(Com)// 获取input元素const input await screen.findByRole(textbox)// 在input输入框中输入await userEvent.type(input, )// 获取input元素const inputEl document.querySelector(input[typetext])// 获取input元素的所有属性const attributes inputEl!.attributeslet ariaDescribedby for (let i 0; i attributes?.length; i) {console.log(attributes[i].name, attributes[i].value)// 找到aria-describedby属性if (attributes[i].name aria-describedby) {// 获取 aria-describedby 属性的值ariaDescribedby attributes[i].value}}// div 的 id 值为 aria-describedby 属性的值const borderDiv document.getElementById(ariaDescribedby)const childrenDiv borderDiv?.querySelectorAll(div)childrenDiv?.forEach(div {// 报错文本console.log(div.textContent)})}) })Jest VSCode 插件 1、Jest 内置测试运行器可以直接运行和调试 jest 测试可以测试某个 describe 或者某个 describe 中的单个 it
http://www.w-s-a.com/news/345077/

相关文章:

  • 做爰全过程的视频网站网络文化经营许可证怎么办
  • 常德市网站建设网站开发用哪个软件好
  • 网站文章怎么更新时间重庆勘察设计网
  • 外卖网站设计企业网站优化做法
  • 专业的营销型网站制作wordpress版权年份
  • 程序员会搭建非法网站吗怎么把wordpress字去掉
  • 牡丹江营商环境建设监督局网站中国档案网站建设的特点
  • 网站欣赏网站欣赏知名企业网站搭建
  • 书店网站建设可行性分析为大型企业设计网络营销方案
  • 北京教育云平台网站建设中国服装设计网站
  • 网络公司专业做网站豌豆荚app下载
  • 网站建设属于什么岗位济宁网站建设_云科网络
  • wordpress网站监测fwa 网站 欣赏
  • 用jsp做的可运行的网站推广网络
  • 电商网站设计论文wordpress子文件夹建站
  • 临沂网站优化如何如何做公司的网站建设
  • 建设部网站 光纤到户沈阳网页设计兼职
  • 企业网站建设作用宁波企业网站推广效果好
  • wordpress课件站模板做网站的公司 贵阳
  • 低价格网站建设网站建设中的板块名称
  • 青岛网站建设华夏h5链接是什么意思
  • 贸易公司如何做网站百度做的网站一般在什么后台
  • 东莞网站设计方案广州做服装电商拿货的网站
  • 部队网站建设设计dede个人网站模板
  • 个人网站怎么自己备案重庆怎样网站推广
  • 做电影网站挣钱吗重庆网站建设技术托管
  • 网站建设用户登录网站商业授权含义
  • 接做室内效果图的网站wordpress制作上传图片
  • 维护一个网站一年多少钱网站微信登录怎么做的
  • 中国建设银行网站E路护航官网如何在招聘网站上选个好公司做销售