<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # Frontend testing standards and style guidelines > 原文:[https://docs.gitlab.com/ee/development/testing_guide/frontend_testing.html](https://docs.gitlab.com/ee/development/testing_guide/frontend_testing.html) * [Vue.js testing](#vuejs-testing) * [Jest](#jest) * [Karma test suite](#karma-test-suite) * [When should I use Jest over Karma?](#when-should-i-use-jest-over-karma) * [Differences to Karma](#differences-to-karma) * [Limitations of jsdom](#limitations-of-jsdom) * [Debugging Jest tests](#debugging-jest-tests) * [Timeout error](#timeout-error) * [What and how to test](#what-and-how-to-test) * [Don’t test the library](#dont-test-the-library) * [Don’t test your mock](#dont-test-your-mock) * [Follow the user](#follow-the-user) * [Common practices](#common-practices) * [How to query DOM elements](#how-to-query-dom-elements) * [Naming unit tests](#naming-unit-tests) * [Testing promises](#testing-promises) * [Manipulating Time](#manipulating-time) * [`setTimeout()` / `setInterval()` in application](#settimeout--setinterval-in-application) * [Waiting in tests](#waiting-in-tests) * [Promises and Ajax calls](#promises-and-ajax-calls) * [Vue rendering](#vue-rendering) * [Events](#events) * [Ensuring that tests are isolated](#ensuring-that-tests-are-isolated) * [Jest best practices](#jest-best-practices) * [Prefer `toBe` over `toEqual` when comparing primitive values](#prefer-tobe-over-toequal-when-comparing-primitive-values) * [Prefer more befitting matchers](#prefer-more-befitting-matchers) * [Avoid using `toBeTruthy` or `toBeFalsy`](#avoid-using-tobetruthy-or-tobefalsy) * [Tricky `toBeDefined` matcher](#tricky-tobedefined-matcher) * [Avoid using `setImmediate`](#avoid-using-setimmediate) * [Factories](#factories) * [Mocking Strategies with Jest](#mocking-strategies-with-jest) * [Stubbing and Mocking](#stubbing-and-mocking) * [Manual module mocks](#manual-module-mocks) * [Where should I put manual mocks?](#where-should-i-put-manual-mocks) * [Manual mock examples](#manual-mock-examples) * [Keep mocks light](#keep-mocks-light) * [Additional mocking techniques](#additional-mocking-techniques) * [Running Frontend Tests](#running-frontend-tests) * [Live testing and focused testing – Jest](#live-testing-and-focused-testing----jest) * [Live testing and focused testing – Karma](#live-testing-and-focused-testing----karma) * [Frontend test fixtures](#frontend-test-fixtures) * [Data-driven tests](#data-driven-tests) * [Gotchas](#gotchas) * [RSpec errors due to JavaScript](#rspec-errors-due-to-javascript) * [Overview of Frontend Testing Levels](#overview-of-frontend-testing-levels) * [Test helpers](#test-helpers) * [Vuex Helper: `testAction`](#vuex-helper-testaction) * [Wait until Axios requests finish](#wait-until-axios-requests-finish) * [Testing with older browsers](#testing-with-older-browsers) * [BrowserStack](#browserstack) * [Firefox](#firefox) * [macOS](#macos) # Frontend testing standards and style guidelines[](#frontend-testing-standards-and-style-guidelines "Permalink") 在 GitLab 上開發前端代碼時,會遇到兩種測試套件. 我們將 Karma 與 Jasmine 和 Jest 一起用于 JavaScript 單元和集成測試,將 RSpec 功能測試與 Capybara 一起用于 e2e(端對端)集成測試. 需要為所有新功能編寫單元和功能測試. 大多數時候,您應該使用[RSpec](https://github.com/rspec/rspec-rails#feature-specs)進行功能測試. 應該編寫回歸測試來修復錯誤,以防止將來再次發生. See the [Testing Standards and Style Guidelines](index.html) page for more information on general testing practices at GitLab. ## Vue.js testing[](#vuejs-testing "Permalink") 如果您正在尋找有關 Vue 組件測試的指南,則可以立即跳至本[部分](../fe_guide/vue.html#testing-vue-components) . ## Jest[](#jest "Permalink") 我們已經開始將前端測試遷移到[Jest](https://jestjs.io)測試框架(另請參見相應的[epic](https://gitlab.com/groups/gitlab-org/-/epics/895) ). 開玩笑的測試可以在 EE 的`/spec/frontend`和`/ee/spec/frontend`中找到. > **Note:** > > 大多數示例都有 Jest 和 Karma 示例. 如果您在發現過程中偶然發現了一些用例,請僅參閱 Karma 示例以解釋代碼中發生的事情. 開玩笑的例子是您應該遵循的例子. ## Karma test suite[](#karma-test-suite "Permalink") 當 GitLab 切換到[Jest 時,](https://jestjs.io)您仍然會在我們的應用程序中找到 Karma 測試. [Karma](http://karma-runner.github.io/)是使用[Jasmine](https://jasmine.github.io/)作為測試框架的測試運行程序. Jest 還使用 Jasmine 作為基礎,這就是為什么它看起來非常相似的原因. 業力測試存在于`/ee/spec/javascripts`中的`spec/javascripts/`和`/ee/spec/javascripts`中. `app/assets/javascripts/behaviors/autosize.js`可能具有相應的`spec/javascripts/behaviors/autosize_spec.js`文件. 請記住,在 CI 環境中,這些測試是在無頭瀏覽器中運行的,您將無權訪問某些必須進行存根的 API,例如[`Notification`](https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/API/notification) . ### When should I use Jest over Karma?[](#when-should-i-use-jest-over-karma "Permalink") 如果您需要更新現有的 Karma 測試文件(可在`spec/javascripts`找到),則無需將整個規范遷移到 Jest. 只需更新 Karma 規范以測試您的更改就可以了. 在單獨的合并請求中遷移到 Jest 可能更合適. 如果創建新的測試文件,則需要在 Jest 中創建它. 這將有助于支持我們的遷移,我們認為您會喜歡使用 Jest. 與往常一樣,請謹慎使用. Jest 解決了我們在 Karma 中遇到的許多問題,并提供了更好的開發人員體驗,但是可能會出現潛在的意外問題(尤其是針對瀏覽器特定功能進行測試). ### Differences to Karma[](#differences-to-karma "Permalink") * Jest 在 Node.js 環境中運行,而不是在瀏覽器中. 運行在瀏覽器中測試玩笑支持[計劃](https://gitlab.com/gitlab-org/gitlab/-/issues/26982) . * 由于 Jest 在 Node.js 環境中運行,因此默認情況下它使用[jsdom](https://github.com/jsdom/jsdom) . 另請參見下面的[限制](#limitations-of-jsdom) . * Jest 無權訪問 Webpack 加載程序或別名. Jest 使用的別名是在其[自己的配置](https://gitlab.com/gitlab-org/gitlab/blob/master/jest.config.js)中定義的. * 對`setTimeout`和`setInterval`所有調用都被模擬掉了. 另請參閱[Jest Timer Mocks](https://jestjs.io/docs/en/timer-mocks) . * `rewire`不需要因為玩笑支撐嘲笑模塊. 另請參見" [手動模擬"](https://jestjs.io/docs/en/manual-mocks) . * 沒有[上下文對象](https://jasmine.github.io/tutorials/your_first_suite#section-The_<code>this</code>_keyword)傳遞給 Jest 中的測試. 這意味著`this.something`在`beforeEach()`和`it()`之間共享`this.something`不起作用. 相反,您應該在需要共享變量的上下文中聲明它們(通過`const` / `let` ). * 以下將導致測試在 Jest 中失敗: * 未模擬的請求. * 未處理的承諾拒絕. * 調用`console.warn` ,包括來自 Vue 之類的庫的警告. ### Limitations of jsdom[](#limitations-of-jsdom "Permalink") [如上所述](#differences-to-karma) ,Jest 使用 jsdom 而不是瀏覽器來運行測試. 這有很多限制,即: * [No scrolling support](https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/browser/Window.js#L623-L625) * [No element sizes or positions](https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/living/nodes/Element-impl.js#L334-L371) * 一般[沒有版面設計引擎](https://github.com/jsdom/jsdom/issues/1322) 另請參閱有關[在瀏覽器中運行 Jest 測試的支持](https://gitlab.com/gitlab-org/gitlab/-/issues/26982)問題. ### Debugging Jest tests[](#debugging-jest-tests "Permalink") 運行`yarn jest-debug`將在調試模式下運行 Jest,從而允許您按照[Jest docs](https://jestjs.io/docs/en/troubleshooting#tests-are-failing-and-you-don-t-know-why)中的說明進行調試/檢查. ### Timeout error[](#timeout-error "Permalink") Jest 的默認超時是在[`/spec/frontend/test_setup.js`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/frontend/test_setup.js)設置的. 如果您的測試超過該時間,它將失敗. 如果無法提高測試性能,則可以使用[`setTestTimeout`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/frontend/helpers/timeout.js)來增加特定測試的超時時間. ``` import { setTestTimeout } from 'helpers/timeout'; describe('Component', () => { it('does something amazing', () => { setTestTimeout(500); // ... }); }); ``` 請記住,每個測試的性能取決于環境. ## What and how to test[](#what-and-how-to-test "Permalink") 在深入了解有關 Jest 特定工作流程(如模擬和間諜)的更具體細節之前,我們應該簡要介紹一下使用 Jest 測試的內容. ### Don’t test the library[](#dont-test-the-library "Permalink") 庫是任何 JavaScript 開發人員生活中不可或缺的一部分. 一般建議是不要測試庫的內部,但是希望庫知道它應該做什么并且自己進行測試覆蓋. 一個一般的例子可能是這樣的 ``` import { convertToFahrenheit } from 'temperatureLibrary' function getFahrenheit(celsius) { return convertToFahrenheit(celsius) } ``` 測試我們的`getFahrenheit`函數沒有任何意義,因為在其下面除了調用庫函數外,什么都沒有做,而且我們可以預期它正在按預期工作. (簡化,我知道) 讓我們看一下 Vue 領域. Vue 是 GitLab JavaScript 代碼庫的關鍵部分. 在編寫 Vue 組件規范時,通常的陷阱是最終測試 Vue 提供的功能,因為這似乎是最容易測試的事情. 這是取自我們代碼庫的示例. ``` // Component { computed: { hasMetricTypes() { return this.metricTypes.length; }, } ``` 這是相應的規格 ``` describe('computed', () => { describe('hasMetricTypes', () => { it('returns true if metricTypes exist', () => { factory({ metricTypes }); expect(wrapper.vm.hasMetricTypes).toBe(2); }); it('returns true if no metricTypes exist', () => { factory(); expect(wrapper.vm.hasMetricTypes).toBe(0); }); }); }); ``` 測試`hasMetricTypes`計算的道具似乎是給定的,但是要測試所計算的屬性是否返回`metricTypes`的長度, `metricTypes`測試 Vue 庫本身. 除了將其添加到測試套件之外,這沒有任何價值. 最好以用戶與之交互的方式對其進行測試. 大概通過模板. 請注意這些測試,因為它們只會使更新邏輯變得比所需的更加脆弱和乏味. 其他庫也是如此. 在[前端單元測試部分中](testing_levels.html#frontend-unit-tests)可以找到更多示例. ### Don’t test your mock[](#dont-test-your-mock "Permalink") 另一個常見的陷阱是規范最終驗證了該模擬程序是否正常運行. 如果使用模擬,則模擬應支持測試,但不應成為測試的目標. **Bad:** ``` const spy = jest.spyOn(idGenerator, 'create') spy.mockImplementation = () = '1234' expect(idGenerator.create()).toBe('1234') ``` **Good:** ``` const spy = jest.spyOn(idGenerator, 'create') spy.mockImplementation = () = '1234' // Actually focusing on the logic of your component and just leverage the controllable mocks output expect(wrapper.find('div').html()).toBe('<div id="1234">...</div>') ``` ### Follow the user[](#follow-the-user "Permalink") 在繁重的組件環境中,單元測試和集成測試之間的界限可能非常模糊. 最重要的準則如下: * 編寫干凈的單元測試,以孤立的方式測試復雜的邏輯部分是否具有實際價值,以防止將來被破壞 * 否則,請嘗試將規格寫得盡可能接近用戶的需求 例如,與手動調用方法并驗證數據結構或計算的屬性相比,使用生成的標記來觸發按鈕單擊并驗證相應更改的標記更好. 在測試通過并提供錯誤的安全感的同時,總是有偶然破壞用戶流的機會. ## Common practices[](#common-practices "Permalink") 接下來,您會發現一些通用的常規做法,它們將作為我們測試套件的一部分. 如果您發現不遵循本指南的內容,最好立即進行修復. ### How to query DOM elements[](#how-to-query-dom-elements "Permalink") 當涉及到測試中的 DOM 元素查詢時,最好以唯一且語義上為目標的元素. 有時這無法切實可行. 在這些情況下,添加測試屬性以簡化選擇器可能是最佳選擇. 優選地,在使用`@vue/test-utils`進行組件測試時,您應該使用組件本身來查詢子組件. 這有助于強制執行該組件的各個單元測試可以涵蓋的特定行為. 否則,請嘗試使用: * 語義屬性(例如`name` (還驗證`name`是否正確設置) * 一個`data-testid`屬性( [由`@vue/test-utils`維護者推薦](https://github.com/vuejs/vue-test-utils/issues/1498#issuecomment-610133465) ) * Vue `ref` (如果使用`@vue/test-utils` ) Examples: ``` it('exists', () => { // Good wrapper.find(FooComponent); wrapper.find('input[name=foo]'); wrapper.find('[data-testid="foo"]'); wrapper.find({ ref: 'foo'}); // Bad wrapper.find('.js-foo'); wrapper.find('.btn-primary'); wrapper.find('.qa-foo-component'); wrapper.find('[data-qa-selector="foo"]'); }); ``` 不建議您僅添加`.js-*`類用于測試目的. 僅當沒有其他可行的選擇時才這樣做. 除 QA 端到端測試外,請勿將`.qa-*`類或`data-qa-selector`屬性用于任何測試. ### Naming unit tests[](#naming-unit-tests "Permalink") 在編寫描述測試塊以測試特定功能/方法時,請使用方法名稱作為描述塊名稱. ``` // Good describe('methodName', () => { it('passes', () => { expect(true).toEqual(true); }); }); // Bad describe('#methodName', () => { it('passes', () => { expect(true).toEqual(true); }); }); // Bad describe('.methodName', () => { it('passes', () => { expect(true).toEqual(true); }); }); ``` ### Testing promises[](#testing-promises "Permalink") 在測試 Promises 時,應始終確保測試是異步的并且拒絕被處理. 現在可以在測試套件中使用`async/await`語法: ``` it('tests a promise', async () => { const users = await fetchUsers() expect(users.length).toBe(42) }); it('tests a promise rejection', async () => { expect.assertions(1); try { await user.getUserName(1); } catch (e) { expect(e).toEqual({ error: 'User with 1 not found.', }); } }); ``` 您也可以使用 Promise 鏈. 在這種情況下,您可以利用`done`回調和`done.fail`發生錯誤. 以下是一些示例: ``` // Good it('tests a promise', done => { promise .then(data => { expect(data).toBe(asExpected); }) .then(done) .catch(done.fail); }); // Good it('tests a promise rejection', done => { promise .then(done.fail) .catch(error => { expect(error).toBe(expectedError); }) .then(done) .catch(done.fail); }); // Bad (missing done callback) it('tests a promise', () => { promise.then(data => { expect(data).toBe(asExpected); }); }); // Bad (missing catch) it('tests a promise', done => { promise .then(data => { expect(data).toBe(asExpected); }) .then(done); }); // Bad (use done.fail in asynchronous tests) it('tests a promise', done => { promise .then(data => { expect(data).toBe(asExpected); }) .then(done) .catch(fail); }); // Bad (missing catch) it('tests a promise rejection', done => { promise .catch(error => { expect(error).toBe(expectedError); }) .then(done); }); ``` ### Manipulating Time[](#manipulating-time "Permalink") 有時我們必須測試時間敏感的代碼. 例如,每隔 X 秒或類似的時間運行一次重復發生的事件. 在這里,您將找到一些應對策略: #### `setTimeout()` / `setInterval()` in application[](#settimeout--setinterval-in-application "Permalink") 如果應用程序本身正在等待一段時間,請模擬等待. 在 Jest 中[,默認情況下](https://gitlab.com/gitlab-org/gitlab/blob/a2128edfee799e49a8732bfa235e2c5e14949c68/jest.config.js#L47)已[完成](https://gitlab.com/gitlab-org/gitlab/blob/a2128edfee799e49a8732bfa235e2c5e14949c68/jest.config.js#L47)此[操作](https://gitlab.com/gitlab-org/gitlab/blob/a2128edfee799e49a8732bfa235e2c5e14949c68/jest.config.js#L47) (另請參見[Jest Timer Mocks](https://jestjs.io/docs/en/timer-mocks) ). 在 Karma 中,您可以使用[Jasmine 模擬時鐘](https://jasmine.github.io/api/2.9/Clock.html) . ``` const doSomethingLater = () => { setTimeout(() => { // do something }, 4000); }; ``` **在:** ``` it('does something', () => { doSomethingLater(); jest.runAllTimers(); expect(something).toBe('done'); }); ``` **在業力中:** ``` it('does something', () => { jasmine.clock().install(); doSomethingLater(); jasmine.clock().tick(4000); expect(something).toBe('done'); jasmine.clock().uninstall(); }); ``` ### Waiting in tests[](#waiting-in-tests "Permalink") 有時,測試需要等待應用程序中的某些事情發生后才能繼續. 避免使用[`setTimeout`](https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)因為它會使等待的原因不清楚,如果在 Karma 中使用的時間大于零,則會減慢我們的測試套件的速度. 而是使用以下方法之一. #### Promises and Ajax calls[](#promises-and-ajax-calls "Permalink") 注冊處理程序函數以等待`Promise`被解決. ``` const askTheServer = () => { return axios .get('/endpoint') .then(response => { // do something }) .catch(error => { // do something else }); }; ``` **在:** ``` it('waits for an Ajax call', async () => { await askTheServer() expect(something).toBe('done'); }); ``` **在業力中:** ``` it('waits for an Ajax call', done => { askTheServer() .then(() => { expect(something).toBe('done'); }) .then(done) .catch(done.fail); }); ``` 如果您無法將處理程序注冊到`Promise` ,例如因為它是在同步 Vue 生命周期掛鉤中執行的,請查看[waitFor](#wait-until-axios-requests-finish)幫助器,或者您可以刷新所有待處理的`Promise` : **在:** ``` it('waits for an Ajax call', () => { synchronousFunction(); jest.runAllTicks(); expect(something).toBe('done'); }); ``` #### Vue rendering[](#vue-rendering "Permalink") 要等到重新渲染 Vue 組件后,請使用等效的[`Vue.nextTick()`](https://vuejs.org/v2/api/#Vue-nextTick)或`vm.$nextTick()` . **在:** ``` it('renders something', () => { wrapper.setProps({ value: 'new value' }); return wrapper.vm.$nextTick().then(() => { expect(wrapper.text()).toBe('new value'); }); }); ``` **in Karma:** ``` it('renders something', done => { wrapper.setProps({ value: 'new value' }); wrapper.vm .$nextTick() .then(() => { expect(wrapper.text()).toBe('new value'); }) .then(done) .catch(done.fail); }); ``` #### Events[](#events "Permalink") 如果應用程序觸發了您需要在測試中等待的事件,請注冊一個包含斷言的事件處理程序: ``` it('waits for an event', done => { eventHub.$once('someEvent', eventHandler); someFunction(); function eventHandler() { expect(something).toBe('done'); done(); } }); ``` 在 Jest 中,您還可以使用`Promise` : ``` it('waits for an event', () => { const eventTriggered = new Promise(resolve => eventHub.$once('someEvent', resolve)); someFunction(); return eventTriggered.then(() => { expect(something).toBe('done'); }); }); ``` ### Ensuring that tests are isolated[](#ensuring-that-tests-are-isolated "Permalink") 測試通常以一種模式進行架構,該模式要求重復設置并破壞被測組件. 這是通過使用`beforeEach`和`afterEach`掛鉤完成的. Example ``` let wrapper; beforeEach(() => { wrapper = mount(Component); }); afterEach(() => { wrapper.destroy(); }); ``` 最初查看此內容時,您會懷疑該組件是在每次測試之前設置的,然后在以后進行了細分,從而在測試之間提供了隔離. 但是,這并不是完全正確的,因為`destroy`方法不會刪除`wrapper`對象上所有已突變的東西. 對于功能組件,destroy 僅從文檔中刪除呈現的 DOM 元素. In order to ensure that a clean wrapper object and DOM are being used in each test, the breakdown of the component should rather be performed as follows: ``` afterEach(() => { wrapper.destroy(); wrapper = null; }); ``` 另請參見[有關`destroy`](https://vue-test-utils.vuejs.org/api/wrapper/#destroy)的[Vue Test Utils 文檔](https://vue-test-utils.vuejs.org/api/wrapper/#destroy) . ### Jest best practices[](#jest-best-practices "Permalink") 在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34209) . #### Prefer `toBe` over `toEqual` when comparing primitive values[](#prefer-tobe-over-toequal-when-comparing-primitive-values "Permalink") [`toBe`](https://jestjs.io/docs/en/expect#tobevalue) [`toEqual`](https://jestjs.io/docs/en/expect#toequalvalue)匹配者. 由于[`toBe`](https://jestjs.io/docs/en/expect#tobevalue)使用[`Object.is`](https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)比較值,因此(默認情況下)比使用`toEqual` . 盡管后者最終將回退以利用[`Object.is`](https://github.com/facebook/jest/blob/master/packages/expect/src/jasmineUtils.ts#L91)獲得原始值,但僅應在需要比較復雜對象的情況下使用它. Examples: ``` const foo = 1; // good expect(foo).toBe(1); // bad expect(foo).toEqual(1); ``` #### Prefer more befitting matchers[](#prefer-more-befitting-matchers "Permalink") Jest 提供了有用的匹配器,例如`toHaveLength`或`toBeUndefined`以使您的測試更具可讀性并產生更易理解的錯誤消息. 查看他們的文檔以獲取[匹配器](https://jestjs.io/docs/en/expect#methods)的[完整列表](https://jestjs.io/docs/en/expect#methods) . Examples: ``` const arr = [1, 2]; // prints: // Expected length: 1 // Received length: 2 expect(arr).toHaveLength(1); // prints: // Expected: 1 // Received: 2 expect(arr.length).toBe(1); // prints: // expect(received).toBe(expected) // Object.is equality // Expected: undefined // Received: "bar" const foo = 'bar'; expect(foo).toBe(undefined); // prints: // expect(received).toBeUndefined() // Received: "bar" const foo = 'bar'; expect(foo).toBeUndefined(); ``` #### Avoid using `toBeTruthy` or `toBeFalsy`[](#avoid-using-tobetruthy-or-tobefalsy "Permalink") Jest 還提供以下匹配器: `toBeTruthy`和`toBeFalsy` . 我們不應該使用它們,因為它們會使測試變弱并產生假陽性結果. 例如,當`someBoolean === null`以及`someBoolean === false`時,會通過`expect(someBoolean).toBeFalsy()` . #### Tricky `toBeDefined` matcher[](#tricky-tobedefined-matcher "Permalink") Jest 有一個棘手的`toBeDefined`匹配器,它可能會產生假陽性測試. 因為它僅[驗證](https://github.com/facebook/jest/blob/master/packages/expect/src/matchers.ts#L204) `undefined`的給定值. ``` // good expect(wrapper.find('foo').exists()).toBe(true); // bad // if finder returns null, the test will pass expect(wrapper.find('foo')).toBeDefined(); ``` #### Avoid using `setImmediate`[](#avoid-using-setimmediate "Permalink") 嘗試避免使用`setImmediate` . `setImmediate`是一個臨時解決方案,可在 I / O 完成后運行您的回調. 而且它不是 Web API 的一部分,因此,我們在單元測試中以 NodeJS 環境為目標. 代替`setImmediate` ,使用`jest.runAllTimers`或`jest.runOnlyPendingTimers`來運行暫掛計時器. 當代碼中有`setInterval`時,后者很有用. **請記住:**我們的 Jest 配置使用假計時器. ## Factories[](#factories "Permalink") TBU ## Mocking Strategies with Jest[](#mocking-strategies-with-jest "Permalink") ### Stubbing and Mocking[](#stubbing-and-mocking "Permalink") Jasmine 提供存根和模擬功能. 在 Karma 和 Jest 中,如何使用它有一些細微的差異. 存根或間諜通常是同義詞. 在 Jest 中,使用`.spyOn`方法非常容易. [官方文檔](https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname)更具挑戰性的部分是模擬,可用于功能甚至依賴項. ### Manual module mocks[](#manual-module-mocks "Permalink") 手動模擬用于模擬整個 Jest 環境中的模塊. 這是一個功能非常強大的測試工具,它通過模擬出在我們的測試環境中不容易使用的模塊來幫助簡化單元測試. > **警告:**如果不應在每個規范中始終采用模擬,則不要使用手動模擬(即,僅少數規范需要使用). 而是考慮在相關規范文件中使用[`jest.mock(..)`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options) (或類似的[`jest.mock(..)`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options)功能). #### Where should I put manual mocks?[](#where-should-i-put-manual-mocks "Permalink") Jest 通過將模擬放置在源模塊旁邊的`__mocks__/`目錄(例如`app/assets/javascripts/ide/__mocks__` )中來支持[手動模塊](https://jestjs.io/docs/en/manual-mocks)模擬. **不要這樣** 我們希望將所有與測試相關的代碼保存在一個地方( `spec/`文件夾). 如果`node_modules`軟件包需要手動模擬,請使用`spec/frontend/__mocks__`文件夾. 這是[`monaco-editor`軟件包](https://gitlab.com/gitlab-org/gitlab/blob/b7f914cddec9fc5971238cdf12766e79fa1629d7/spec/frontend/__mocks__/monaco-editor/index.js#L1)的[Jest 模擬](https://gitlab.com/gitlab-org/gitlab/blob/b7f914cddec9fc5971238cdf12766e79fa1629d7/spec/frontend/__mocks__/monaco-editor/index.js#L1)示例. 如果 CE 模塊需要手動模擬,請將其放在`spec/frontend/mocks/ce` . * `spec/frontend/mocks/ce`文件將從`app/assets/javascripts`模擬相應的 CE 模塊,從而鏡像源模塊的路徑. * 示例: `spec/frontend/mocks/ce/lib/utils/axios_utils`將模擬模塊`~/lib/utils/axios_utils` . * 我們尚不支持模擬 EE 模塊. * 如果找到了不存在源模塊的模擬,則測試套件將失敗. 目前尚不支持"虛擬"模擬或與源模塊沒有 1 對 1 關聯的模擬. #### Manual mock examples[](#manual-mock-examples "Permalink") * 模擬[`mocks/axios_utils`](https://gitlab.com/gitlab-org/gitlab/blob/bd20aeb64c4eed117831556c54b40ff4aee9bfd1/spec/frontend/mocks/ce/lib/utils/axios_utils.js#L1)此模擬很有用,因為我們不希望任何未經模擬的請求通過任何測試. 另外,我們能夠注入一些測試助手,例如`axios.waitForAll` . * [`__mocks__/mousetrap/index.js`](https://gitlab.com/gitlab-org/gitlab/blob/cd4c086d894226445be9d18294a060ba46572435/spec/frontend/__mocks__/mousetrap/index.js#L1)此模擬很有用,因為該模塊本身使用 webpack 可以理解的 AMD 格式,但與玩笑的環境不兼容. 該模擬不會刪除任何行為,僅提供與 es6 兼容的包裝器. * [`__mocks__/monaco-editor/index.js`](https://gitlab.com/gitlab-org/gitlab/blob/b7f914cddec9fc5971238cdf12766e79fa1629d7/spec/frontend/__mocks__/monaco-editor/index.js) - This mock is helpful because the Monaco package is completely incompatible in a Jest environment. In fact, webpack requires a special loader to make it work. This mock simply makes this package consumable by Jest. ### Keep mocks light[](#keep-mocks-light "Permalink") 全局模擬會引入魔術,并且從技術上講可以減少測試的覆蓋范圍. 當嘲笑被視為有利可圖時: * 保持模擬簡短而集中. * 請在模擬中留下為什么有必要的頂級評論. ### Additional mocking techniques[](#additional-mocking-techniques "Permalink") 請查閱[官方的 Jest 文檔](https://jestjs.io/docs/en/jest-object#mock-modules) ,以獲取有關可用模擬功能的完整概述. ## Running Frontend Tests[](#running-frontend-tests "Permalink") 要運行前端測試,您需要以下命令: * `rake frontend:fixtures` (re-)generates [fixtures](#frontend-test-fixtures). * `yarn test`執行測試. * `yarn jest`執行 Jest 測試. 只要固定裝置不變, `yarn test`就足夠了(并節省了一些時間). ### Live testing and focused testing – Jest[](#live-testing-and-focused-testing----jest "Permalink") 在測試套件上工作時,您可能希望以監視模式運行這些規范,因此它們會在每次保存時自動重新運行. ``` # Watch and rerun all specs matching the name icon yarn jest --watch icon # Watch and rerun one specifc file yarn jest --watch path/to/spec/file.spec.js ``` 您也可以在不使用`--watch`標志的情況下運行一些重點測試 ``` # Run specific jest file yarn jest ./path/to/local_spec.js # Run specific jest folder yarn jest ./path/to/folder/ # Run all jest files which path contain term yarn jest term ``` ### Live testing and focused testing – Karma[](#live-testing-and-focused-testing----karma "Permalink") 業力允許類似的東西,但是成本更高. 用`yarn run karma-start`運行 Karma 將編譯 JavaScript 資產并在`http://localhost:9876/`上運行服務器,在該服務器上它將自動在連接到它的任何瀏覽器上運行測試. 您可以一次在多個瀏覽器上輸入該 URL,以使其在每個瀏覽器上并行運行測試. 當 Karma 運行時,您所做的任何更改都會立即觸發**整個測試套件**的重新編譯和重新**測試** ,因此您可以立即查看是否使用所做的更改破壞了測試. 您可以使用[針對 Jasmine 的](https://jasmine.github.io/2.5/focused_specs.html)測試或排除測試(使用`fdescribe`或`xdescribe` )來使 Karma 僅在您使用特定功能時運行所需的測試,但是請確保在提交代碼時刪除這些指令. 通過使用參數`--filter-spec`或 short `-f`過濾運行測試,也可以僅在特定的文件夾或文件上運行 Karma: ``` # Run all files yarn karma-start # Run specific spec files yarn karma-start --filter-spec profile/account/components/update_username_spec.js # Run specific spec folder yarn karma-start --filter-spec profile/account/components/ # Run all specs which path contain vue_shared or vie yarn karma-start -f vue_shared -f vue_mr_widget ``` 您還可以使用 glob 語法來匹配文件. 請記住在引號周圍加上引號,否則您的 shell 可能會將其拆分為多個參數: ``` # Run all specs named `file_spec` within the IDE subdirectory yarn karma -f 'spec/javascripts/ide/**/file_spec.js' ``` ## Frontend test fixtures[](#frontend-test-fixtures "Permalink") 添加到 HAML 模板(在`app/views/` )或向后端發出 Ajax 請求的代碼具有要求后端提供 HTML 或 JSON 的測試. 這些測試的夾具位于: * `spec/frontend/fixtures/` ,用于在 CE 中運行測試. * `ee/spec/frontend/fixtures/` ,用于在 EE 中運行測試. 燈具文件位于: * Karma 測試套件由[jasmine-jquery 提供](https://github.com/velesin/jasmine-jquery) . * 開玩笑地使用`spec/frontend/helpers/fixtures.js` . 以下是適用于 Karma 和 Jest 的測試示例: ``` it('makes a request', () => { const responseBody = getJSONFixture('some/fixture.json'); // loads spec/frontend/fixtures/some/fixture.json axiosMock.onGet(endpoint).reply(200, responseBody); myButton.click(); // ... }); it('uses some HTML element', () => { loadFixtures('some/page.html'); // loads spec/frontend/fixtures/some/page.html and adds it to the DOM const element = document.getElementById('#my-id'); // ... }); ``` HTML 和 JSON 固定裝置是使用 RSpec 從后端視圖和控制器生成的(請參閱`spec/frontend/fixtures/*.rb` ). 對于每個燈具, `response`變量的內容存儲在輸出文件中. 如果測試標記為`type: :request`或`type: :controller`則此變量將自動設置. 可以使用`bin/rake frontend:fixtures`命令來重新生成`bin/rake frontend:fixtures`但是您也可以單獨生成它們,例如`bin/rspec spec/frontend/fixtures/merge_requests.rb` . 創建新的固定裝置時,通常有必要在`(ee/)spec/controllers/`或`(ee/)spec/requests/`查看端點的相應測試. ## Data-driven tests[](#data-driven-tests "Permalink") 與[RSpec 的參數化測試](best_practices.html#table-based--parameterized-tests)類似,Jest 支持以下數據驅動的測試: * 使用[`test.each`](https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout)單獨測試(別名為`it.each` ). * 使用[`describe.each`](https://jestjs.io/docs/en/api#describeeachtable-name-fn-timeout)的測試組. 這些對于減少測試中的重復很有用. 每個選項都可以采用數據值數組或帶標簽的模板文字. 例如: ``` // function to test const icon = status => status ? 'pipeline-passed' : 'pipeline-failed' const message = status => status ? 'pipeline-passed' : 'pipeline-failed' // test with array block it.each([ [false, 'pipeline-failed'], [true, 'pipeline-passed'] ])('icon with %s will return %s', (status, icon) => { expect(renderPipeline(status)).toEqual(icon) } ); ``` ``` // test suite with tagged template literal block describe.each` status | icon | message ${false} | ${'pipeline-failed'} | ${'Pipeline failed - boo-urns'} ${true} | ${'pipeline-passed'} | ${'Pipeline succeeded - win!'} `('pipeline component', ({ status, icon, message }) => { it(`returns icon ${icon} with status ${status}`, () => { expect(icon(status)).toEqual(message) }) it(`returns message ${message} with status ${status}`, () => { expect(message(status)).toEqual(message) }) }); ``` ## Gotchas[](#gotchas "Permalink") ### RSpec errors due to JavaScript[](#rspec-errors-due-to-javascript "Permalink") 默認情況下,RSpec 單元測試不會在無頭瀏覽器中運行 JavaScript,而僅依賴于檢查 rails 生成的 HTML. 如果集成測試依賴 JavaScript 才能正確運行,則需要確保將規范配置為在運行測試時啟用 JavaScript. 如果不這樣做,您會看到規范運行器發出的模糊錯誤消息. To enable a JavaScript driver in an `rspec` test, add `:js` to the individual spec or the context block containing multiple specs that need JavaScript enabled: ``` # For one spec it 'presents information about abuse report', :js do # assertions... end describe "Admin::AbuseReports", :js do it 'presents information about abuse report' do # assertions... end it 'shows buttons for adding to abuse report' do # assertions... end end ``` ## Overview of Frontend Testing Levels[](#overview-of-frontend-testing-levels "Permalink") 有關前端測試級別的主要信息,請參見" [測試級別"頁面](testing_levels.html) . 與前端開發相關的測試可以在以下位置找到: * `spec/javascripts/` ,用于業力測試 * `spec/frontend/` ,用于 Is 測試 * `spec/features/` ,用于 RSpec 測試 RSpec 運行完整的[功能測試](testing_levels.html#frontend-feature-tests) ,而 Jest 和 Karma 目錄包含[前端單元測試](testing_levels.html#frontend-unit-tests) , [前端組件測試](testing_levels.html#frontend-component-tests)和[前端集成測試](testing_levels.html#frontend-integration-tests) . `spec/javascripts/`所有測試最終都將遷移到`spec/frontend/` (另請參見[#52483](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52483) ). 在 2018 年 5 月之前, `features/`還包含 Spinach 運行的功能測試. 這些測試已于 2018 年 5 月從代碼庫中刪除( [#23036](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/23036) ). 另請參閱[有關測試 Vue 組件的說明](../fe_guide/vue.html#testing-vue-components) . ## Test helpers[](#test-helpers "Permalink") ### Vuex Helper: `testAction`[](#vuex-helper-testaction "Permalink") 根據[官方文檔](https://vuex.vuejs.org/guide/testing.html) ,我們提供了一個幫助程序,可以簡化測試操作: ``` testAction( actions.actionName, // action { }, // params to be passed to action state, // state [ { type: types.MUTATION}, { type: types.MUTATION_1, payload: {}}, ], // mutations committed [ { type: 'actionName', payload: {}}, { type: 'actionName1', payload: {}}, ] // actions dispatched done, ); ``` 在[`spec/javascripts/ide/stores/actions_spec.jsspec/javascripts/ide/stores/actions_spec.js`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/javascripts/ide/stores/actions_spec.js) . ### Wait until Axios requests finish[](#wait-until-axios-requests-finish "Permalink") The Axios Utils mock module located in `spec/frontend/mocks/ce/lib/utils/axios_utils.js` contains two helper methods for Jest tests that spawn HTTP requests. These are very useful if you don’t have a handle to the request’s Promise, for example when a Vue component does a request as part of its life cycle. * `waitFor(url, callback)` :對`url`的請求完成后(成功或失敗)運行`callback` . * `waitForAll(callback)` :所有未完成的請求完成后,運行`callback` . 如果沒有待處理的請求,則在下一個刻度上運行`callback` . 這兩個函數運行`callback` (使用請求結束后的下一個滴答`setImmediate()`以允許任何`.then()`或`.catch()`處理程序來運行. ## Testing with older browsers[](#testing-with-older-browsers "Permalink") 某些回歸僅影響特定的瀏覽器版本. 我們可以按照以下步驟使用 Firefox 或 BrowserStack 在特定的瀏覽器中安裝和測試: ### BrowserStack[](#browserstack "Permalink") [BrowserStack](https://www.browserstack.com/)可以測試 1200 多種移動設備和瀏覽器. 您可以直接通過[實時應用程序](https://www.browserstack.com/live)使用它,也可以安裝[chrome 擴展程序](https://chrome.google.com/webstore/detail/browserstack/nkihdmlheodkdfojglpcjjmioefjahjb)以便于訪問. 使用保存在 GitLab [共享 1Password 帳戶](https://about.gitlab.com/handbook/security/#1password-guide)的**Engineering**庫中的憑據登錄到 BrowserStack. ### Firefox[](#firefox "Permalink") #### macOS[](#macos "Permalink") 您可以從發布的 FTP 服務器[https://ftp.mozilla.org/pub/firefox/releases/](https://ftp.mozilla.org/pub/firefox/releases/)下載任何較舊版本的 Firefox: 1. 從網站上選擇一個版本,在本例中為`50.0.1` . 2. 轉到 mac 文件夾. 3. 選擇您喜歡的語言,您將在其中找到 DMG 軟件包并下載. 4. 將應用程序拖放到"應用`Applications`文件夾以外的任何其他文件夾中. 5. 將應用程序重命名為`Firefox_Old` . 6. 將應用程序移至"應用`Applications`文件夾. 7. 打開終端,然后運行`/Applications/Firefox_Old.app/Contents/MacOS/firefox-bin -profilemanager`以創建特定于該 Firefox 版本的新配置文件. 8. 創建配置文件后,請退出應用程序,然后像平常一樣再次運行它. 現在,您可以使用較舊的 Firefox 版本. * * * [Return to Testing documentation](index.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看