From 61e1d9275c0886418c679ce1cefa2c85c40e45c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Wed, 31 Jul 2019 17:53:01 +0200 Subject: [PATCH 1/4] =?UTF-8?q?test:=20=F0=9F=92=8D=20add=20Vue=20tests=20?= =?UTF-8?q?for=20type,=20dblclick,=20selectoptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/vue/dblclick.js | 125 ++++++++++++++++++ __tests__/vue/selectoptions.js | 229 +++++++++++++++++++++++++++++++++ __tests__/vue/type.js | 99 ++++++++++++++ 3 files changed, 453 insertions(+) create mode 100644 __tests__/vue/dblclick.js create mode 100644 __tests__/vue/selectoptions.js create mode 100644 __tests__/vue/type.js diff --git a/__tests__/vue/dblclick.js b/__tests__/vue/dblclick.js new file mode 100644 index 00000000..4010d3d3 --- /dev/null +++ b/__tests__/vue/dblclick.js @@ -0,0 +1,125 @@ +import { render, cleanup } from "@testing-library/vue"; +import "@testing-library/jest-dom/extend-expect"; +import userEvent from "../../src"; + +afterEach(cleanup); + +describe("userEvent.dblClick", () => { + it.each(["input", "textarea"])( + "should fire the correct events for <%s>", + type => { + const events = []; + const eventsHandler = jest.fn(evt => events.push(evt.type)); + const { getByTestId } = render({ + render: function(h) { + return h(type, { + attrs: { + "data-testid": "element" + }, + on: { + mouseover: eventsHandler, + mousemove: eventsHandler, + mousedown: eventsHandler, + focus: eventsHandler, + mouseup: eventsHandler, + click: eventsHandler, + dblclick: eventsHandler + } + }); + } + }); + + userEvent.dblClick(getByTestId("element")); + + expect(events).toEqual([ + "mouseover", + "mousemove", + "mousedown", + "focus", + "mouseup", + "click", + "mousedown", + "mouseup", + "click", + "dblclick" + ]); + } + ); + + it('should fire the correct events for ', () => { + const events = []; + const eventsHandler = jest.fn(evt => events.push(evt.type)); + + const { getByTestId } = render({ + render: function(h) { + return h("input", { + attrs: { + type: "checkbox", + "data-testid": "element" + }, + on: { + mouseover: eventsHandler, + mousemove: eventsHandler, + mousedown: eventsHandler, + focus: eventsHandler, + mouseup: eventsHandler, + click: eventsHandler, + change: eventsHandler + } + }); + } + }); + + userEvent.dblClick(getByTestId("element")); + + expect(events).toEqual([ + "mouseover", + "mousemove", + "mousedown", + "mouseup", + "click", + "change", + "mousedown", + "mouseup", + "click", + "change" + ]); + + expect(getByTestId("element")).toHaveProperty("checked", false); + }); + + it("should fire the correct events for
", () => { + const events = []; + const eventsHandler = jest.fn(evt => events.push(evt.type)); + const { getByTestId } = render({ + render: function(h) { + return h("div", { + attrs: { + "data-testid": "div" + }, + on: { + mouseover: eventsHandler, + mousemove: eventsHandler, + mousedown: eventsHandler, + focus: eventsHandler, + mouseup: eventsHandler, + click: eventsHandler, + change: eventsHandler + } + }); + } + }); + + userEvent.dblClick(getByTestId("div")); + expect(events).toEqual([ + "mouseover", + "mousemove", + "mousedown", + "mouseup", + "click", + "mousedown", + "mouseup", + "click" + ]); + }); +}); diff --git a/__tests__/vue/selectoptions.js b/__tests__/vue/selectoptions.js new file mode 100644 index 00000000..0d178ef8 --- /dev/null +++ b/__tests__/vue/selectoptions.js @@ -0,0 +1,229 @@ +import { render, cleanup } from "@testing-library/vue"; +import "@testing-library/jest-dom/extend-expect"; +import userEvent from "../../src"; + +afterEach(cleanup); + +describe("userEvent.selectOptions", () => { + it.each(["select", "select multiple"])( + "should fire the correct events for <%s>", + type => { + const events = []; + const eventsHandler = jest.fn(evt => events.push(evt.type)); + const multiple = type === "select multiple"; + const eventHandlers = { + mouseover: eventsHandler, + mousemove: eventsHandler, + mousedown: eventsHandler, + focus: eventsHandler, + mouseup: eventsHandler, + click: eventsHandler + }; + + const { getByTestId } = render({ + render: function(h) { + return h( + "select", + { + attrs: { + "data-testid": "element", + ...(multiple && { multiple: true }) + }, + on: eventHandlers + }, + [ + h("option", { attrs: { value: "1" } }, "1"), + h("option", { attrs: { value: "2" } }, "2"), + h("option", { attrs: { value: "3" } }, "3") + ] + ); + } + }); + + userEvent.selectOptions(getByTestId("element"), "1"); + + expect(events).toEqual([ + "mouseover", + "mousemove", + "mousedown", + "focus", + "mouseup", + "click", + "mouseover", // The events repeat because we click on the child OPTION too + "mousemove", // But these specifically are the events bubbling up to the ", () => { + function handleEvent(evt) { + const optValue = parseInt(evt.target.value); + events[optValue] = [...(events[optValue] || []), evt.type]; + } + + const events = []; + const eventsHandler = jest.fn(handleEvent); + const eventHandlers = { + mouseover: eventsHandler, + mousemove: eventsHandler, + mousedown: eventsHandler, + focus: eventsHandler, + mouseup: eventsHandler, + click: eventsHandler + }; + + const { getByTestId } = render({ + render: function(h) { + return h( + "select", + { + attrs: { + "data-testid": "element" + } + }, + [ + h("option", { attrs: { value: "1" }, on: eventHandlers }, "1"), + h("option", { attrs: { value: "2" }, on: eventHandlers }, "2"), + h("option", { attrs: { value: "3" }, on: eventHandlers }, "3") + ] + ); + } + }); + + userEvent.selectOptions(getByTestId("element"), ["2"]); + + expect(events[1]).toBe(undefined); + expect(events[3]).toBe(undefined); + expect(events[2]).toEqual([ + "mouseover", + "mousemove", + "mousedown", + "focus", + "mouseup", + "click" + ]); + }); + + it("should fire the correct events on selected OPTION children with + + + + + ` + }); + + userEvent.selectOptions(getByTestId("element"), ["1", "3"]); + + expect(getByTestId("val1").selected).toBe(true); + expect(getByTestId("val2").selected).toBe(false); + expect(getByTestId("val3").selected).toBe(true); + }); + + it("sets the selected prop on the selected OPTION using htmlFor", () => { + const { getByTestId } = render({ + template: ` +
+ + +
` + }); + + userEvent.selectOptions(getByTestId("element"), "2"); + + expect(getByTestId("val1").selected).toBe(false); + expect(getByTestId("val2").selected).toBe(true); + expect(getByTestId("val3").selected).toBe(false); + }); + + it("sets the selected prop on the selected OPTION using nested SELECT", () => { + const { getByTestId } = render({ + template: ` +
+ +
` + }); + + userEvent.selectOptions(getByTestId("element"), "2"); + + expect(getByTestId("val1").selected).toBe(false); + expect(getByTestId("val2").selected).toBe(true); + expect(getByTestId("val3").selected).toBe(false); + }); +}); diff --git a/__tests__/vue/type.js b/__tests__/vue/type.js new file mode 100644 index 00000000..b888d013 --- /dev/null +++ b/__tests__/vue/type.js @@ -0,0 +1,99 @@ +import { cleanup, render, wait, fireEvent } from "@testing-library/vue"; +import "@testing-library/jest-dom/extend-expect"; +import userEvent from "../../src"; + +afterEach(cleanup); + +const renderComponent = (type, events = {}) => + render({ + render: function(h) { + return h(type, { + attrs: { "data-testid": "input" }, + on: events + }); + } + }); + +describe("userEvent.type", () => { + it.each(["input", "textarea"])("should type text in <%s>", type => { + const input = jest.fn(); + + const { getByTestId } = renderComponent(type, { input }); + + const text = "Hello, world!"; + userEvent.type(getByTestId("input"), text); + + expect(input).toHaveBeenCalledTimes(text.length); + expect(getByTestId("input")).toHaveProperty("value", text); + }); + + it("should not type when event.preventDefault() is called", () => { + const input = jest.fn(); + const change = jest.fn(); + const keydown = jest + .fn() + .mockImplementation(event => event.preventDefault()); + + const { getByTestId } = renderComponent("input", { + input, + keydown, + change + }); + + const text = "Hello, world!"; + userEvent.type(getByTestId("input"), text); + expect(keydown).toHaveBeenCalledTimes(text.length); + expect(change).toHaveBeenCalledTimes(0); + // expect(input).toHaveBeenCalledTimes(0); + // expect(getByTestId("input")).not.toHaveProperty("value", text); + }); + + it("should delay the typing when opts.delay is not 0", async () => { + jest.useFakeTimers(); + const change = jest.fn(); + const input = jest.fn(); + const { getByTestId } = renderComponent("input", { change, input }); + const text = "Hello, world!"; + const delay = 10; + + userEvent.type(getByTestId("input"), text, { + delay + }); + + expect(input).not.toHaveBeenCalled(); + expect(getByTestId("input")).not.toHaveProperty("value", text); + + for (let i = 0; i < text.length; i++) { + jest.advanceTimersByTime(delay); + + await wait(() => expect(input).toHaveBeenCalledTimes(i + 1)); + + expect(getByTestId("input")).toHaveProperty( + "value", + text.slice(0, i + 1) + ); + } + + // Vue's change event is not emitted until blurring the input + expect(change).not.toHaveBeenCalled(); + fireEvent.blur(getByTestId("input")); + await wait(() => expect(change).toHaveBeenCalledTimes(1)); + }); + + it.each(["input", "textarea"])( + "should type text in <%s> all at once", + type => { + const input = jest.fn(); + + const { getByTestId } = renderComponent(type, { input }); + const text = "Hello, world!"; + + userEvent.type(getByTestId("input"), text, { + allAtOnce: true + }); + + expect(getByTestId("input")).toHaveProperty("value", text); + expect(input).toHaveBeenCalledTimes(1); + } + ); +}); From b6f8965df231361035cfe0dfd1347e627058f6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Tue, 13 Aug 2019 10:21:03 +0200 Subject: [PATCH 2/4] Bump VTL to 2.0 --- package-lock.json | 70 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e926657..46e9684b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2382,15 +2382,43 @@ } }, "@testing-library/vue": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@testing-library/vue/-/vue-1.1.0.tgz", - "integrity": "sha512-7y3Y0wv8QBGem3c1LZAkWJFK0QS7LTg38eIqgDZ2cRwFyEhsTkIIeKJ0A4C9iMZ7lZKtPuisWmb+Joc+rCzEtQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/vue/-/vue-2.0.0.tgz", + "integrity": "sha512-6hsQQ89QQPQCUak9N2DJXcWR2MeVQYdrt4S6N0YEf4UYDJf30SWYfHho8dHCsypCo34HHdqDXPdEQ7ktTCsxqA==", "dev": true, "requires": { - "@testing-library/dom": "^5.2.0", - "@vue/test-utils": "^1.0.0-beta.29", - "vue": "^2.6.10", - "vue-template-compiler": "^2.6.10" + "@testing-library/dom": "^6.0.0", + "@vue/test-utils": "^1.0.0-beta.29" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@testing-library/dom": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.0.0.tgz", + "integrity": "sha512-B5XTz3uMsbqbdR9CZlnwpZjTE3fCWuqRkz/zvDc2Ej/vuHmTM0Ur2v0XPwr7usWfGIBsahEK5HL1E91+4IFiBg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@sheerun/mutationobserver-shim": "^0.3.2", + "aria-query": "3.0.0", + "pretty-format": "^24.8.0", + "wait-for-expect": "^1.3.0" + } + }, + "wait-for-expect": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.3.0.tgz", + "integrity": "sha512-8fJU7jiA96HfGPt+P/UilelSAZfhMBJ52YhKzlmZQvKEZU2EcD1GQ0yqGB6liLdHjYtYAoGVigYwdxr5rktvzA==", + "dev": true + } } }, "@types/babel__core": { @@ -4441,12 +4469,6 @@ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, - "de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6782,12 +6804,6 @@ "minimalistic-assert": "^1.0.1" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -16451,22 +16467,6 @@ "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", "dev": true }, - "vue": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==", - "dev": true - }, - "vue-template-compiler": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", - "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", - "dev": true, - "requires": { - "de-indent": "^1.0.2", - "he": "^1.1.0" - } - }, "w3c-hr-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", diff --git a/package.json b/package.json index 0d324e6b..d2df3cff 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@testing-library/dom": "5.6.0", "@testing-library/jest-dom": "4.0.0", "@testing-library/react": "8.0.5", - "@testing-library/vue": "1.1.0", + "@testing-library/vue": "^2.0.0", "all-contributors-cli": "6.8.1", "babel-core": "7.0.0-bridge.0", "babel-jest": "24.8.0", From 2285c650da28df39c344ab96daef8240b0784fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Tue, 13 Aug 2019 10:24:16 +0200 Subject: [PATCH 3/4] Add vue peerDependencies --- package-lock.json | 28 ++++++++++++++++++++++++++++ package.json | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 46e9684b..1cdfe2fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4469,6 +4469,12 @@ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6804,6 +6810,12 @@ "minimalistic-assert": "^1.0.1" } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -16467,6 +16479,22 @@ "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", "dev": true }, + "vue": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", + "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==", + "dev": true + }, + "vue-template-compiler": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", + "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, "w3c-hr-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", diff --git a/package.json b/package.json index d2df3cff..55076e83 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,9 @@ "react-dom": "16.8.6", "regenerator-runtime": "0.13.2", "semantic-release": "15.13.18", - "travis-deploy-once": "5.0.11" + "travis-deploy-once": "5.0.11", + "vue": "^2.6.10", + "vue-template-compiler": "^2.6.10" }, "peerDependencies": { "@testing-library/dom": ">=5" From 32aad7ec3578953cfddf09ee478fb51c5b9b3a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Tue, 13 Aug 2019 10:25:07 +0200 Subject: [PATCH 4/4] Enable preventDefault failing test --- __tests__/vue/type.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/vue/type.js b/__tests__/vue/type.js index b888d013..6f758ee9 100644 --- a/__tests__/vue/type.js +++ b/__tests__/vue/type.js @@ -44,8 +44,8 @@ describe("userEvent.type", () => { userEvent.type(getByTestId("input"), text); expect(keydown).toHaveBeenCalledTimes(text.length); expect(change).toHaveBeenCalledTimes(0); - // expect(input).toHaveBeenCalledTimes(0); - // expect(getByTestId("input")).not.toHaveProperty("value", text); + expect(input).toHaveBeenCalledTimes(0); + expect(getByTestId("input")).not.toHaveProperty("value", text); }); it("should delay the typing when opts.delay is not 0", async () => {