From 550d9e29f864d59e18b9af1712fe64df0f9b8c8b Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Mon, 16 Sep 2024 14:34:59 +0100 Subject: [PATCH 1/7] refactor(browser-type-check): rename file and improve test readability --- .../browser-type-check.spec.ts | 31 ---------------- .../browser-type-check.test.ts | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+), 31 deletions(-) delete mode 100644 src/__internal__/utils/helpers/browser-type-check/browser-type-check.spec.ts create mode 100644 src/__internal__/utils/helpers/browser-type-check/browser-type-check.test.ts diff --git a/src/__internal__/utils/helpers/browser-type-check/browser-type-check.spec.ts b/src/__internal__/utils/helpers/browser-type-check/browser-type-check.spec.ts deleted file mode 100644 index 1fefee17f1..0000000000 --- a/src/__internal__/utils/helpers/browser-type-check/browser-type-check.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import browserCheck, { isSafari } from "."; - -describe("browserTypeCheck", () => { - it('returns true if "chrome" exists', () => { - const _window = { chrome: { foo: true }, sidebar: undefined }; - expect(browserCheck(_window)).toEqual(true); - }); - it('returns true if "sidebar" exists', () => { - const _window = { chrome: undefined, sidebar: { foo: true } }; - expect(browserCheck(_window)).toEqual(true); - }); - it('returns true if "chrome" and "sidebar" exist', () => { - const _window = { chrome: { foo: true }, sidebar: { foo: true } }; - expect(browserCheck(_window)).toEqual(true); - }); - it('returns false if neither "chrome" or "sidebar" exists', () => { - const _window = {}; - expect(browserCheck(_window)).toEqual(false); - }); -}); - -describe("isSafari", () => { - it('returns true if vendor includes "Apple"', () => { - const navigator = { vendor: "Apple" }; - expect(isSafari(navigator as Navigator)).toEqual(true); - }); - it('returns false if vendor does not include "Apple"', () => { - const navigator = { vendor: "foo" }; - expect(isSafari(navigator as Navigator)).toEqual(false); - }); -}); diff --git a/src/__internal__/utils/helpers/browser-type-check/browser-type-check.test.ts b/src/__internal__/utils/helpers/browser-type-check/browser-type-check.test.ts new file mode 100644 index 0000000000..33697e90f4 --- /dev/null +++ b/src/__internal__/utils/helpers/browser-type-check/browser-type-check.test.ts @@ -0,0 +1,37 @@ +import browserCheck, { isSafari } from "."; + +describe("browserTypeCheck", () => { + test('returns true when the "chrome" property is present in the browser object', () => { + const browser = { chrome: { foo: true }, sidebar: undefined }; + const result = browserCheck(browser); + expect(result).toEqual(true); + }); + test('returns true when the "sidebar" property is present in the browser object', () => { + const browser = { chrome: undefined, sidebar: { foo: true } }; + const result = browserCheck(browser); + expect(result).toEqual(true); + }); + test('returns true when the "chrome" and "sidebar" properties are present in the browser object', () => { + const browser = { chrome: { foo: true }, sidebar: { foo: true } }; + const result = browserCheck(browser); + expect(result).toEqual(true); + }); + test('returns false when the "chrome" and "sidebar" properties are not present in the browser object', () => { + const browser = {}; + const result = browserCheck(browser); + expect(result).toEqual(false); + }); +}); + +describe("isSafari", () => { + test('returns true when the vendor string contains "Apple"', () => { + const navigator = { vendor: "Apple" } as Navigator; + const result = isSafari(navigator); + expect(result).toEqual(true); + }); + test('returns false when the vendor string does not contain "Apple"', () => { + const navigator = { vendor: "foo" } as Navigator; + const result = isSafari(navigator); + expect(result).toEqual(false); + }); +}); From 33ced586ea45ddc6e0d34a12ddb44b3bae9b8850 Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Tue, 17 Sep 2024 09:49:09 +0100 Subject: [PATCH 2/7] refactor(events): rename test file and improve test readability --- .../utils/helpers/events/events.spec.ts | 291 --------------- .../utils/helpers/events/events.test.ts | 332 ++++++++++++++++++ 2 files changed, 332 insertions(+), 291 deletions(-) delete mode 100644 src/__internal__/utils/helpers/events/events.spec.ts create mode 100644 src/__internal__/utils/helpers/events/events.test.ts diff --git a/src/__internal__/utils/helpers/events/events.spec.ts b/src/__internal__/utils/helpers/events/events.spec.ts deleted file mode 100644 index 50e07b8196..0000000000 --- a/src/__internal__/utils/helpers/events/events.spec.ts +++ /dev/null @@ -1,291 +0,0 @@ -import Events from "./events"; - -describe("Events", () => { - describe("isEventType", () => { - describe("when event type matches passed type", () => { - it("returns true", () => { - expect( - Events.isEventType({ type: "click" } as Event, "click") - ).toBeTruthy(); - }); - }); - - describe("when event type does NOT match passed type", () => { - it("returns false", () => { - expect( - Events.isEventType({ type: "click" } as Event, "keyUp") - ).toBeFalsy(); - }); - }); - }); - describe("isKeyboardEvent", () => { - it.each(["keyup", "keydown", "keypress"])( - "returns true when event type is %s", - (type) => { - expect(Events.isKeyboardEvent({ type } as Event)).toBeTruthy(); - } - ); - - it("returns false when event type is not a keyboard event type", () => { - expect(Events.isKeyboardEvent({ type: "click" } as Event)).toBeFalsy(); - }); - }); - - describe("isEnterOrSpaceKey", () => { - describe("when event is not a key up event", () => { - it("returns false", () => { - expect( - Events.isEnterOrSpaceKey({ type: "click" } as KeyboardEvent) - ).toBeFalsy(); - }); - }); - - describe("when event is a keyup event", () => { - describe("when key is not the enter key", () => { - it("returns false", () => { - expect( - Events.isEnterOrSpaceKey({ - type: "keyup", - key: "Backspace", - } as KeyboardEvent) - ).toBeFalsy(); - }); - }); - - describe("key is the enter key", () => { - it("returns true", () => { - expect( - Events.isEnterOrSpaceKey({ - type: "keyup", - key: "Enter", - } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - - describe("key is the space key", () => { - it("returns true", () => { - expect( - Events.isEnterOrSpaceKey({ - type: "keyup", - key: " ", - } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - }); - }); - - describe("isNumberKey", () => { - it("returns false when a non number key is pressed", () => { - expect(Events.isNumberKey({ key: "a" } as KeyboardEvent)).toBeFalsy(); - }); - - it.each(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])( - "returns true when a number is pressed (%s)", - (key) => { - expect(Events.isNumberKey({ key } as KeyboardEvent)).toBeTruthy(); - } - ); - }); - - describe("isLeftKey", () => { - it("returns false when the left key is not pressed", () => { - expect( - Events.isLeftKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the left key is pressed", () => { - expect( - Events.isLeftKey({ key: "ArrowLeft" } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - - describe("isUpKey", () => { - it("returns false when the up key is not pressed", () => { - expect(Events.isUpKey({ key: "Backspace" } as KeyboardEvent)).toBeFalsy(); - }); - - it("returns true when the up key is pressed", () => { - expect(Events.isUpKey({ key: "ArrowUp" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isRightKey", () => { - it("returns false when the right key is not pressed", () => { - expect( - Events.isRightKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the right key is pressed", () => { - expect( - Events.isRightKey({ key: "ArrowRight" } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - - describe("isDownKey", () => { - it("returns false when the down key is not pressed", () => { - expect( - Events.isDownKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the down key is pressed", () => { - expect( - Events.isDownKey({ key: "ArrowDown" } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - - describe("isEscKey", () => { - it("returns false when the ESC key is not pressed", () => { - expect( - Events.isEscKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the ESC key is pressed", () => { - expect(Events.isEscKey({ key: "Escape" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isEnterKey", () => { - it("returns false when the Enter key is not pressed", () => { - expect( - Events.isEnterKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the Enter key is pressed", () => { - expect(Events.isEnterKey({ key: "Enter" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isTabKey", () => { - it("returns false when the Tab key is not pressed", () => { - expect( - Events.isTabKey({ key: "Backspace" } as KeyboardEvent) - ).toBeFalsy(); - }); - - it("returns true when the Tab key is pressed", () => { - expect(Events.isTabKey({ key: "Tab" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isShiftKey", () => { - it("returns false when a Shift key is not pressed", () => { - expect(Events.isShiftKey({ key: "Tab" } as KeyboardEvent)).toBeFalsy(); - }); - - it("returns true when the Shift key is pressed", () => { - expect( - Events.isShiftKey({ shiftKey: true } as KeyboardEvent) - ).toBeTruthy(); - }); - }); - - describe("isSpaceKey", () => { - it("returns false when a Space key is not pressed", () => { - expect(Events.isSpaceKey({ key: "Tab" } as KeyboardEvent)).toBeFalsy(); - }); - - it("returns true when the Space key is pressed", () => { - expect(Events.isSpaceKey({ key: " " } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isHomeKey", () => { - it("returns false when the home key is not pressed", () => { - expect(Events.isHomeKey({ key: "End" } as KeyboardEvent)).toBeFalsy(); - }); - - it("returns true when the home key is pressed", () => { - expect(Events.isHomeKey({ key: "Home" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("isEndKey", () => { - it("returns false when the end key is not pressed", () => { - expect(Events.isEndKey({ key: "Home" } as KeyboardEvent)).toBeFalsy(); - }); - - it("returns true when the end key is pressed", () => { - expect(Events.isEndKey({ key: "End" } as KeyboardEvent)).toBeTruthy(); - }); - }); - - describe("composedPath", () => { - it("returns an empty array if there is no target", () => { - expect(Events.composedPath(new CustomEvent("click"))).toEqual([]); - }); - - it("returns an empty array if target is null", () => { - const ev = { - target: null, - }; - - expect(Events.composedPath(ev as CustomEvent)).toEqual([]); - }); - - it("returns an empty array if there is no parent element", () => { - const ev = { - target: document as EventTarget, - }; - - expect(Events.composedPath(ev as CustomEvent)).toEqual([]); - }); - - it("returns the path from event.composedPath() if it is available", () => { - const path = Symbol("path"); - const composedPath = jest.fn(); - composedPath.mockReturnValue(path); - const ev = new CustomEvent("click"); - ev.composedPath = composedPath; - expect(Events.composedPath(ev)).toBe(path); - }); - - it.each([ - [ - "a DOMElement", - (path: EventTarget[], li: EventTarget) => { - const ev = { - target: li, - }; - - expect(Events.composedPath(ev as CustomEvent)).toEqual(path); - }, - ], - [ - "an Enzyme ReactWrapper", - (path: EventTarget[], li: HTMLElement) => { - const ev = new CustomEvent("click", { - detail: { - enzymeTestingTarget: li, - }, - }); - - expect(Events.composedPath(ev)).toEqual(path); - }, - ], - ])( - "builds the path if it is not available on the element from %s", - (str, assertion) => { - const div = document.createElement("div"); - const ul = document.createElement("ul"); - const li = document.createElement("li"); - - ul.appendChild(li); - div.appendChild(ul); - - const path = [div, ul, li]; - - assertion(path, li); - } - ); - }); -}); diff --git a/src/__internal__/utils/helpers/events/events.test.ts b/src/__internal__/utils/helpers/events/events.test.ts new file mode 100644 index 0000000000..a138c995cc --- /dev/null +++ b/src/__internal__/utils/helpers/events/events.test.ts @@ -0,0 +1,332 @@ +import Events from "./events"; + +describe("isEventType", () => { + test("Returns true when the event type and passed type match", () => { + const event = { type: "click" } as Event; + const result = Events.isEventType(event, "click"); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type and passed type do not match", () => { + const event = { type: "click" } as Event; + const result = Events.isEventType(event, "keyUp"); + + expect(result).toBeFalsy(); + }); +}); + +describe("isKeyboardEvent", () => { + test.each(["keyup", "keydown", "keypress"])( + "Returns true when the event type is a keyboard event type (%s)", + (type) => { + const event = { type } as Event; + const result = Events.isKeyboardEvent(event); + + expect(result).toBeTruthy(); + } + ); + + test("Returns false when the event type is not a keyboard event type", () => { + const event = { type: "click" } as Event; + const result = Events.isKeyboardEvent(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isEnterOrSpaceKey", () => { + test("Returns true when the event type is a keyup event, and the key is the Enter key", () => { + const event = { type: "keyup", key: "Enter" } as KeyboardEvent; + const result = Events.isEnterOrSpaceKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns true when the event type is a keyup event, and the key is the Space key", () => { + const event = { type: "keyup", key: " " } as KeyboardEvent; + const result = Events.isEnterOrSpaceKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is a keyup event, but the key is not the Enter key or the Space key", () => { + const event = { type: "keyup", key: "Backspace" } as KeyboardEvent; + const result = Events.isEnterOrSpaceKey(event); + + expect(result).toBeFalsy(); + }); + + test("Returns false when the event type is not a keyup event", () => { + const event = { type: "keydown" } as KeyboardEvent; + const result = Events.isEnterOrSpaceKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isNumberKey", () => { + test.each(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])( + "Returns true when the event type is a number key event (%s)", + (key) => { + const event = { key } as KeyboardEvent; + const result = Events.isNumberKey(event); + + expect(result).toBeTruthy(); + } + ); + + test("Returns false when the event type is not a number key event", () => { + const event = { key: "a" } as KeyboardEvent; + const result = Events.isNumberKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isLeftKey", () => { + test("Returns false when the event type is not a left key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isLeftKey(event); + + expect(result).toBeFalsy(); + }); + + test("Returns true when the event type is a left key event", () => { + const event = { key: "ArrowLeft" } as KeyboardEvent; + const result = Events.isLeftKey(event); + + expect(result).toBeTruthy(); + }); +}); + +describe("isUpKey", () => { + test("Returns true when the event type is an up key event", () => { + const event = { key: "ArrowUp" } as KeyboardEvent; + const result = Events.isUpKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not an up key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isUpKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isRightKey", () => { + test("Returns true when the event type is a right key event", () => { + const event = { key: "ArrowRight" } as KeyboardEvent; + const result = Events.isRightKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a right key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isRightKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isDownKey", () => { + test("Returns true when the event type is a down key event", () => { + const event = { key: "ArrowDown" } as KeyboardEvent; + const result = Events.isDownKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a down key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isDownKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isEscKey", () => { + test("Returns true when the event type is an Escape key event", () => { + const event = { key: "Escape" } as KeyboardEvent; + const result = Events.isEscKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not an Escape key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isEscKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isEnterKey", () => { + test("Returns true when the event type is an Enter key event", () => { + const event = { key: "Enter" } as KeyboardEvent; + const result = Events.isEnterKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not an Enter key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isEnterKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isTabKey", () => { + test("Returns true when the event type is a Tab key event", () => { + const event = { key: "Tab" } as KeyboardEvent; + const result = Events.isTabKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a Tab key event", () => { + const event = { key: "Backspace" } as KeyboardEvent; + const result = Events.isTabKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isShiftKey", () => { + test("Returns true when the event type is a Shift key event", () => { + const event = { shiftKey: true } as KeyboardEvent; + const result = Events.isShiftKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a Shift key event", () => { + const event = { key: "Tab" } as KeyboardEvent; + const result = Events.isShiftKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isSpaceKey", () => { + test("Returns true when the event type is a Space key event", () => { + const event = { key: " " } as KeyboardEvent; + const result = Events.isSpaceKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a Space key event", () => { + const event = { key: "Tab" } as KeyboardEvent; + const result = Events.isSpaceKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isHomeKey", () => { + test("Returns true when the event type is a Home key event", () => { + const event = { key: "Home" } as KeyboardEvent; + const result = Events.isHomeKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not a Home key event", () => { + const event = { key: "End" } as KeyboardEvent; + const result = Events.isHomeKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("isEndKey", () => { + test("Returns true when the event type is an End key event", () => { + const event = { key: "End" } as KeyboardEvent; + const result = Events.isEndKey(event); + + expect(result).toBeTruthy(); + }); + + test("Returns false when the event type is not an End key event", () => { + const event = { key: "Home" } as KeyboardEvent; + const result = Events.isEndKey(event); + + expect(result).toBeFalsy(); + }); +}); + +describe("composedPath", () => { + test("Returns an empty array if there is no target", () => { + const event = new CustomEvent("click"); + const result = Events.composedPath(event); + + expect(result).toEqual([]); + }); + + test("Returns an empty array if target is null", () => { + const event = { target: null } as CustomEvent; + const result = Events.composedPath(event); + + expect(result).toEqual([]); + }); + + test("Returns an empty array if there is no parent element", () => { + const event = { target: document as EventTarget } as CustomEvent; + const result = Events.composedPath(event); + + expect(result).toEqual([]); + }); + + test("Returns the path from event.composedPath() if it is available", () => { + const path = Symbol("path"); + const composedPath = jest.fn(); + composedPath.mockReturnValue(path); + + const event = new CustomEvent("click"); + event.composedPath = composedPath; + const result = Events.composedPath(event); + + expect(result).toBe(path); + }); + + test("Builds path from DOM elements if event.composedPath is unavailable", () => { + const div = document.createElement("div"); + const ul = document.createElement("ul"); + const li = document.createElement("li"); + + ul.appendChild(li); + div.appendChild(ul); + + const path = [div, ul, li]; + const event = ({ target: li } as unknown) as CustomEvent; + const result = Events.composedPath(event); + + expect(result).toEqual(path); + }); + + /* TODO: FE-6826 Investigate if `composedPath` is still required post removal of Enzyme. */ + + test("Builds the path if it is not available on the element from a ReactWrapper", () => { + const div = document.createElement("div"); + const ul = document.createElement("ul"); + const li = document.createElement("li"); + + ul.appendChild(li); + div.appendChild(ul); + + const path = [div, ul, li]; + const event = new CustomEvent("click", { + detail: { + enzymeTestingTarget: li, + }, + }); + const result = Events.composedPath(event); + + expect(result).toEqual(path); + }); +}); From da9a948d62dc511404a23aeb47989e9d6f2de2da Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Tue, 17 Sep 2024 16:03:18 +0100 Subject: [PATCH 3/7] refactor(guid): rename test file and improve test readability and quality --- src/__internal__/utils/helpers/guid/guid.spec.ts | 12 ------------ src/__internal__/utils/helpers/guid/guid.test.ts | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) delete mode 100644 src/__internal__/utils/helpers/guid/guid.spec.ts create mode 100644 src/__internal__/utils/helpers/guid/guid.test.ts diff --git a/src/__internal__/utils/helpers/guid/guid.spec.ts b/src/__internal__/utils/helpers/guid/guid.spec.ts deleted file mode 100644 index 3ca9760309..0000000000 --- a/src/__internal__/utils/helpers/guid/guid.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import guid from "."; - -describe("guid", () => { - it("returns a 36 character id", () => { - expect(guid().length).toEqual(36); - }); - - it("returns a unique id", () => { - const id = guid(); - expect(guid()).not.toEqual(id); - }); -}); diff --git a/src/__internal__/utils/helpers/guid/guid.test.ts b/src/__internal__/utils/helpers/guid/guid.test.ts new file mode 100644 index 0000000000..9f743bff26 --- /dev/null +++ b/src/__internal__/utils/helpers/guid/guid.test.ts @@ -0,0 +1,11 @@ +import guid from "."; + +test("should generate a guid with a length of 36 characters", () => { + expect(guid().length).toEqual(36); +}); + +test("should generate a unique guid each time it is called", () => { + const guids = Array.from({ length: 5 }, () => guid()); + const uniqueGuids = new Set(guids); + expect(uniqueGuids.size).toEqual(5); +}); From 6ce82dbbec1193629d4114fafb129635ddc478f6 Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Tue, 17 Sep 2024 16:53:34 +0100 Subject: [PATCH 4/7] refactor(tags): rename test file and improve test readability --- .../utils/helpers/tags/tags.spec.ts | 26 ------------------- .../utils/helpers/tags/tags.test.ts | 23 ++++++++++++++++ 2 files changed, 23 insertions(+), 26 deletions(-) delete mode 100644 src/__internal__/utils/helpers/tags/tags.spec.ts create mode 100644 src/__internal__/utils/helpers/tags/tags.test.ts diff --git a/src/__internal__/utils/helpers/tags/tags.spec.ts b/src/__internal__/utils/helpers/tags/tags.spec.ts deleted file mode 100644 index 086ec64209..0000000000 --- a/src/__internal__/utils/helpers/tags/tags.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import tagComponent from "./tags"; - -describe("tagComponent", () => { - describe("when no additional tag props are sent", () => { - it("returns the component name tag", () => { - expect(tagComponent("my-component", {})).toEqual({ - "data-component": "my-component", - }); - }); - }); - - describe("when role and element props are sent", () => { - it("adds those to the tagProps object", () => { - expect( - tagComponent("my-component", { - "data-element": "my-component", - "data-role": "contacts", - }) - ).toEqual({ - "data-component": "my-component", - "data-element": "my-component", - "data-role": "contacts", - }); - }); - }); -}); diff --git a/src/__internal__/utils/helpers/tags/tags.test.ts b/src/__internal__/utils/helpers/tags/tags.test.ts new file mode 100644 index 0000000000..c51ea7453d --- /dev/null +++ b/src/__internal__/utils/helpers/tags/tags.test.ts @@ -0,0 +1,23 @@ +import tagComponent from "./tags"; + +test("tagProps object should only return a data-component tag populated with the component name, when no additional tag props are set", () => { + const tag = tagComponent("my-component", {}); + + expect(tag).toEqual({ + "data-component": "my-component", + }); +}); + +test("tagProps object should return data-element and data-role tags if provided", () => { + const attributes = { + "data-element": "my-component", + "data-role": "contacts", + }; + const tag = tagComponent("my-component", attributes); + + expect(tag).toEqual({ + "data-component": "my-component", + "data-element": "my-component", + "data-role": "contacts", + }); +}); From 7dbd32c0673beb95daf8c33e1a3dee818e73e01e Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Wed, 18 Sep 2024 09:46:00 +0100 Subject: [PATCH 5/7] refactor(logger): rename test file and improve test readability and quality --- src/__internal__/utils/logger/logger.spec.ts | 24 -------------------- src/__internal__/utils/logger/logger.test.ts | 24 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 src/__internal__/utils/logger/logger.spec.ts create mode 100644 src/__internal__/utils/logger/logger.test.ts diff --git a/src/__internal__/utils/logger/logger.spec.ts b/src/__internal__/utils/logger/logger.spec.ts deleted file mode 100644 index 552e0d0d3b..0000000000 --- a/src/__internal__/utils/logger/logger.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Logger from "."; -import { expectConsoleOutput } from "../../../__spec_helper__/__internal__/test-utils"; - -const message = "Hello World!"; - -describe("Logger", () => { - beforeEach(() => { - Logger.setEnabledState(true); - }); - - it("does not output to the console when enabled is false", () => { - Logger.setEnabledState(false); - jest.spyOn(console, "warn"); - Logger.deprecate(message); - // eslint-disable-next-line no-console - expect(console.warn).not.toHaveBeenCalled(); - }); - - it("ouputs an warn to the console with a deprecation prefix", () => { - const assert = expectConsoleOutput(`[Deprecation]${message}`, "warn"); - Logger.deprecate(`[Deprecation]${message}`); - assert(); - }); -}); diff --git a/src/__internal__/utils/logger/logger.test.ts b/src/__internal__/utils/logger/logger.test.ts new file mode 100644 index 0000000000..e56a92d4eb --- /dev/null +++ b/src/__internal__/utils/logger/logger.test.ts @@ -0,0 +1,24 @@ +import Logger from "."; + +test("should not output a warning to the console when logging is disabled", () => { + Logger.setEnabledState(false); + const consoleWarnSpy = jest + .spyOn(console, "warn") + .mockImplementation(() => {}); + Logger.deprecate("This is a deprecation message"); + + expect(consoleWarnSpy).not.toHaveBeenCalled(); +}); + +test("should output a warning to the console with a deprecation prefix when logging is enabled", () => { + Logger.setEnabledState(true); + const consoleWarnSpy = jest + .spyOn(console, "warn") + .mockImplementation(() => {}); + Logger.deprecate("This is a deprecation message"); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + "[Deprecation] This is a deprecation message" + ); + consoleWarnSpy.mockReset(); +}); From 3f6e89ad5adb426ef939bb7c1f6249d16b2c6267 Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Wed, 18 Sep 2024 15:08:40 +0100 Subject: [PATCH 6/7] refactor(validation-message): convert enzyme tests to RTL --- .../validation-message.component.tsx | 1 + .../validation-message.spec.tsx | 76 ------------------- .../validation-message.test.tsx | 45 +++++++++++ 3 files changed, 46 insertions(+), 76 deletions(-) delete mode 100644 src/__internal__/validation-message/validation-message.spec.tsx create mode 100644 src/__internal__/validation-message/validation-message.test.tsx diff --git a/src/__internal__/validation-message/validation-message.component.tsx b/src/__internal__/validation-message/validation-message.component.tsx index 18bdb1cdd0..cbaa3c0404 100644 --- a/src/__internal__/validation-message/validation-message.component.tsx +++ b/src/__internal__/validation-message/validation-message.component.tsx @@ -24,6 +24,7 @@ const ValidationMessage = ({ {validation} diff --git a/src/__internal__/validation-message/validation-message.spec.tsx b/src/__internal__/validation-message/validation-message.spec.tsx deleted file mode 100644 index c9d576d663..0000000000 --- a/src/__internal__/validation-message/validation-message.spec.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from "react"; -import { mount } from "enzyme"; -import ValidationMessage from "."; -import StyledValidationMessage from "./validation-message.style"; -import { assertStyleMatch } from "../../__spec_helper__/__internal__/test-utils"; -import { ValidationMessageProps } from "./validation-message.component"; - -const render = (props: ValidationMessageProps) => - mount(); - -const validationWithStrings = [ - ["error", "warning"], - [undefined, "warning"], -]; -const validationWithBooleans: (string | boolean | undefined)[][] = [ - [true, "string"], - [undefined, true], -]; - -const computeId = (id?: string) => (id === "warning" ? "warningText" : id); - -const addColorId = (arr: (string | undefined)[][]) => - arr.map((subArr) => [...subArr, computeId(subArr[0] || subArr[1])]); - -describe("ValidationMessage component", () => { - let wrapper; - - it.each(addColorId(validationWithStrings))( - "applies the expected styling when passed error string equals `%s` and warning string equals `%s`", - (error, warning) => { - wrapper = render({ error, warning }); - - assertStyleMatch( - { - color: error - ? "var(--colorsSemanticNegative500)" - : "var(--colorsSemanticCaution600)", - fontWeight: error ? "bold" : "normal", - marginTop: "0px", - marginBottom: "8px", - }, - wrapper.find(StyledValidationMessage) - ); - } - ); - - it.each(validationWithStrings)( - "renders the expected message when passed error string equals `%s` and warning string equals `%s`", - (error, warning) => { - wrapper = render({ error, warning }); - const expected = error || warning; - - expect(wrapper.text()).toEqual(expected); - } - ); - - it.each(validationWithBooleans)( - "does not render message when passed error is `%s` and warning is `%s`", - (error, warning) => { - wrapper = render({ error, warning }); - expect(wrapper.text()).toEqual(""); - } - ); - - it("does not render message when no props passed", () => { - wrapper = render({}); - expect(wrapper.text()).toEqual(""); - }); - - it("validationId should be passed to the message", () => { - const mockId = "foo"; - wrapper = render({ validationId: mockId, error: "bar" }); - - expect(wrapper.find(StyledValidationMessage).prop("id")).toEqual(mockId); - }); -}); diff --git a/src/__internal__/validation-message/validation-message.test.tsx b/src/__internal__/validation-message/validation-message.test.tsx new file mode 100644 index 0000000000..9b00d48ebe --- /dev/null +++ b/src/__internal__/validation-message/validation-message.test.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import ValidationMessage from "."; + +test("renders only the error message when both `error` and `warning` props are provided as strings", () => { + render(); + + const validationMessage = screen.getByTestId("validation-message"); + expect(validationMessage).toHaveTextContent("error"); +}); + +test("renders only the warning message when the `warning` prop is a string and the `error` prop is undefined", () => { + render(); + + const validationMessage = screen.getByTestId("validation-message"); + expect(validationMessage).toHaveTextContent("warning"); +}); + +test("does not render when the `error` prop is true, and the `warning` prop is a string", () => { + render(); + + const validationMessage = screen.queryByTestId("validation-message"); + expect(validationMessage).not.toBeInTheDocument(); +}); + +test("does not render when the `error` prop is undefined, and the `warning` prop is true", () => { + render(); + + const validationMessage = screen.queryByTestId("validation-message"); + expect(validationMessage).not.toBeInTheDocument(); +}); + +test("does not render when the `error` and `warning` props are not provided", () => { + render(); + + const validationMessage = screen.queryByTestId("validation-message"); + expect(validationMessage).not.toBeInTheDocument(); +}); + +test("sets the 'id' attribute to the value of the `validationId` prop", () => { + render(); + + const validationMessage = screen.getByTestId("validation-message"); + expect(validationMessage).toHaveAttribute("id", "foo"); +}); From d2fe9536652a96ff7c643d0c85580726d3e67d6b Mon Sep 17 00:00:00 2001 From: "tom.davies" Date: Thu, 19 Sep 2024 15:44:32 +0100 Subject: [PATCH 7/7] refactor(validation-icon): convert enzyme tests to RTL --- .../validations/validation-icon.spec.tsx | 236 ------------------ .../validations/validation-icon.test.tsx | 213 ++++++++++++++++ 2 files changed, 213 insertions(+), 236 deletions(-) delete mode 100644 src/__internal__/validations/validation-icon.spec.tsx create mode 100644 src/__internal__/validations/validation-icon.test.tsx diff --git a/src/__internal__/validations/validation-icon.spec.tsx b/src/__internal__/validations/validation-icon.spec.tsx deleted file mode 100644 index e7f9b13607..0000000000 --- a/src/__internal__/validations/validation-icon.spec.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import React from "react"; -import { mount, ReactWrapper } from "enzyme"; -import { act } from "react-dom/test-utils"; - -import ValidationIcon from "./validation-icon.component"; -import ValidationIconStyle from "./validation-icon.style"; -import { InputContext, InputGroupContext } from "../input-behaviour"; -import Tooltip from "../../components/tooltip"; -import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils"; -import Icon from "../../components/icon/icon.component"; - -function renderWithInputContext( - inputContextValue = {}, - inputGroupContextValue = {} -) { - return mount( - - - - - - ); -} - -describe("ValidationIcon", () => { - testStyledSystemMargin((props) => ( - - )); - - it.each([ - [{ error: "Message" }, "error"], - [{ warning: "Message" }, "warning"], - [{ info: "Message" }, "info"], - ])( - "renders with a proper icon if validation prop is passed as string", - (validation, iconType) => { - const wrapper = mount(); - expect(wrapper.find(ValidationIconStyle).prop("validationType")).toEqual( - iconType - ); - } - ); - - it.each([[{ error: true }], [{ warning: true }], [{ info: true }]])( - "does not render any icon if validation prop is a string", - (validation) => { - const wrapper = mount(); - expect(wrapper.find(ValidationIconStyle).exists()).toBe(false); - } - ); - - it('tooltips "position" prop should be "right"', () => { - const wrapper = mount(); - const tooltipProps = wrapper.find(Tooltip).props(); - expect(tooltipProps.position).toBe("right"); - }); - - it("shows the tooltip if input context has focus", () => { - const tooltip = renderWithInputContext({ hasFocus: true }).find(Tooltip); - expect(tooltip.props().isVisible).toEqual(true); - }); - - it("shows the tooltip if input context has mouse over", () => { - const tooltip = renderWithInputContext({ hasMouseOver: true }).find( - Tooltip - ); - expect(tooltip.props().isVisible).toEqual(true); - }); - - it("shows the tooltip if input group context has focus", () => { - const tooltip = renderWithInputContext({}, { hasFocus: true }).find( - Tooltip - ); - expect(tooltip.props().isVisible).toEqual(true); - }); - - it("shows the tooltip if input group context has mouse over", () => { - const tooltip = renderWithInputContext({}, { hasMouseOver: true }).find( - Tooltip - ); - expect(tooltip.props().isVisible).toEqual(true); - }); - - it("shows the Tooltip if component has mouse over event", () => { - const wrapper = mount(); - wrapper.simulate("mouseover"); - expect(wrapper.find(Tooltip).props().isVisible).toEqual(true); - }); - - it("hides the Tooltip if component has mouse leave event", () => { - const wrapper = mount(); - wrapper.simulate("mouseover"); - wrapper.simulate("mouseleave"); - expect(wrapper.find(Tooltip).props().isVisible).toEqual(false); - }); - - it("shows the Tooltip if component has focus event", () => { - const wrapper = mount(); - wrapper.simulate("focus"); - expect(wrapper.find(Tooltip).props().isVisible).toEqual(true); - }); - - it("hides the Tooltip if component has blur event", () => { - const wrapper = mount(); - wrapper.simulate("focus"); - wrapper.simulate("blur"); - expect(wrapper.find(Tooltip).props().isVisible).toEqual(false); - }); - - it("passes tooltipId to the Tooltip component", () => { - const tooltipId = "tooltip-id"; - const wrapper = mount( - - ); - expect(wrapper.find(Tooltip).props().id).toEqual(tooltipId); - }); - - describe("event handlers", () => { - describe("validation", () => { - it("onFocus", () => { - const mockOnFocus = jest.fn(); - const wrapper = mount( - - ); - act(() => { - wrapper.find(ValidationIconStyle).props().onFocus(); - }); - expect(mockOnFocus).toHaveBeenCalled(); - }); - - it("onBlur", () => { - const mockOnBlur = jest.fn(); - const wrapper = mount( - - ); - act(() => { - wrapper.find(ValidationIconStyle).props().onBlur(); - }); - expect(mockOnBlur).toHaveBeenCalled(); - }); - }); - }); - - describe("tooltipFlipOverrides", () => { - it("sets Tooltip to flip `top` and `bottom` when `isPartOfInput` and no `tooltipFlipOverrides` set", () => { - const wrapper = mount(); - expect(wrapper.find(Tooltip).props().flipOverrides).toEqual([ - "top", - "bottom", - ]); - }); - - it("sets Tooltip to flip to given placements defined by `tooltipFlipOverrides`", () => { - const wrapper = mount( - - ); - expect(wrapper.find(Tooltip).props().flipOverrides).toEqual([ - "left", - "top", - ]); - }); - - it("throws an error when value is not an array", () => { - const mockGlobal = jest - .spyOn(global.console, "error") - .mockImplementation(() => undefined); - const errorMessage = `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`; - - expect(() => { - mount( - - ); - }).toThrow(errorMessage); - - mockGlobal.mockReset(); - }); - - it("throws an error when value is an array but contains an invalid element", () => { - const mockGlobal = jest - .spyOn(global.console, "error") - .mockImplementation(() => undefined); - const errorMessage = `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`; - - expect(() => { - mount( - - ); - }).toThrow(errorMessage); - - mockGlobal.mockReset(); - }); - }); - - describe("when the tooltipId prop is set", () => { - const mockId = "foo"; - let wrapper: ReactWrapper; - - beforeEach(() => { - wrapper = mount(); - }); - - it("then aria-describedby prop on the Icon component should have the same value", () => { - expect(wrapper.find(Icon).prop("aria-describedby")).toBe(mockId); - }); - }); - - describe("when the tooltipId prop is not set", () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - wrapper = mount(); - }); - - it("then aria-describedby prop on the Icon component should have the same value as it's tooltipId prop", () => { - expect(wrapper.find(Icon).prop("aria-describedby")).toBe( - wrapper.find(Icon).prop("tooltipId") - ); - }); - }); -}); diff --git a/src/__internal__/validations/validation-icon.test.tsx b/src/__internal__/validations/validation-icon.test.tsx new file mode 100644 index 0000000000..1d3c09830b --- /dev/null +++ b/src/__internal__/validations/validation-icon.test.tsx @@ -0,0 +1,213 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; + +import ValidationIcon from "./validation-icon.component"; +import { InputContext, InputGroupContext } from "../input-behaviour"; +import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils"; + +testStyledSystemMargin((props) => ); + +test("renders an icon with the error type when the `error` prop is a string", () => { + render(); + + const icon = screen.getByTestId("icon-error"); + expect(icon).toBeVisible(); +}); + +test("renders an icon with the warning type when the `warning` prop is a string", () => { + render(); + + const icon = screen.getByTestId("icon-warning"); + expect(icon).toBeVisible(); +}); + +test("renders an icon with the info type when the `info` prop is a string", () => { + render(); + + const icon = screen.getByTestId("icon-info"); + expect(icon).toBeVisible(); +}); + +test("does not render any icon if the `error` prop is a boolean", () => { + render(); + + const icon = screen.queryByTestId(/^icon-/); + expect(icon).not.toBeInTheDocument(); +}); + +test("does not render any icon if the `warning` prop is a boolean", () => { + render(); + + const icon = screen.queryByTestId(/^icon-/); + expect(icon).not.toBeInTheDocument(); +}); + +test("does not render any icon if the `info` prop is a boolean", () => { + render(); + + const icon = screen.queryByTestId(/^icon-/); + expect(icon).not.toBeInTheDocument(); +}); + +test("renders a tooltip if the `hasFocus` prop is true on the input context provider", () => { + render( + + + + ); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip if the `hasMouseOver` prop is true on the input context provider", () => { + render( + + + + ); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip if the `hasFocus` prop is true on the input group context provider", () => { + render( + + + + ); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip if the `hasMouseOver` prop is true on the input group context provider", () => { + render( + + + + ); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip when the validation icon is hovered", async () => { + render(); + + const user = userEvent.setup(); + const validationIcon = screen.getByTestId("icon-error"); + await user.hover(validationIcon); + + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip when the validation icon is hovered, then is not rendered when un hovered", async () => { + render(); + + const user = userEvent.setup(); + const validationIcon = screen.getByTestId("icon-error"); + + await user.hover(validationIcon); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); + + await user.unhover(validationIcon); + expect(tooltip).not.toBeVisible(); +}); + +test("renders a tooltip when the validation icon is focused", () => { + render(); + + const validationIcon = screen.getByTestId("icon-error"); + validationIcon.focus(); + + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); +}); + +test("renders a tooltip when validation icon is focused, then is not rendered on blur", async () => { + render(); + + const user = userEvent.setup(); + const validationIcon = screen.getByTestId("icon-error"); + + validationIcon.focus(); + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeVisible(); + + await user.tab(); + expect(tooltip).not.toBeVisible(); +}); + +test("sets the 'id' attribute on the tooltip via the `tooltipId` prop on the validation icon", () => { + render(); + + const validationIcon = screen.getByTestId("icon-error"); + validationIcon.focus(); + + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toHaveAttribute("id", "foo"); +}); + +test("triggers a passed function via the `onFocus` prop when the validation icon is focused", () => { + const mockOnFocus = jest.fn(); + render(); + + const validationIcon = screen.getByTestId("icon-error"); + validationIcon.focus(); + + expect(mockOnFocus).toHaveBeenCalled(); +}); + +test("triggers a passed function via the `onBlur` prop when the validation icon is blurred", async () => { + const mockOnBlur = jest.fn(); + render(); + + const user = userEvent.setup(); + const validationIcon = screen.getByTestId("icon-error"); + + await user.click(validationIcon); + await user.tab(); + + expect(mockOnBlur).toHaveBeenCalled(); +}); + +test("throws an error when `tooltipFlipOverride` props value is not an array", () => { + const mockGlobal = jest + .spyOn(global.console, "error") + .mockImplementation(() => undefined); + const errorMessage = `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`; + + expect(() => { + render( + + ); + }).toThrow(errorMessage); + + mockGlobal.mockReset(); +}); + +test("throws an error when the `tooltipFlipOverride` props value is an array, but contains an invalid element", () => { + const mockGlobal = jest + .spyOn(global.console, "error") + .mockImplementation(() => undefined); + const errorMessage = `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`; + + expect(() => { + render( + + ); + }).toThrow(errorMessage); + + mockGlobal.mockReset(); +});