@@ -3,27 +3,65 @@ import * as sinon from "sinon";
33import { clearBodyStyle , setBodyStyle } from "./body" ;
44
55describe ( "setBodyStyle" , ( ) => {
6+ let dummyDocumentElement : Document ;
7+ let dummyElement : HTMLElement ;
8+ let elementCreatorMock : sinon . SinonStub < Parameters < Document [ "createElement" ] > , ReturnType < Document [ "createElement" ] > > ;
9+ let elementAttributeSetterSpy : sinon . SinonSpy < Parameters < Element [ "setAttribute" ] > , ReturnType < Element [ "setAttribute" ] > > ;
10+ let childAppenderSpy : sinon . SinonSpy < Parameters < Node [ "appendChild" ] > , ReturnType < Node [ "appendChild" ] > > ;
11+
12+ beforeEach ( ( ) => {
13+ elementAttributeSetterSpy = sinon . spy ( ) as any ;
14+ dummyElement = { setAttribute : elementAttributeSetterSpy , textContent : "" } as any ;
15+
16+ elementCreatorMock = sinon . mock ( ) . returns ( dummyElement ) as any ;
17+ childAppenderSpy = sinon . spy ( ) as any ;
18+ dummyDocumentElement = { createElement : elementCreatorMock , head : { appendChild : childAppenderSpy } } as any ;
19+ } ) ;
20+ afterEach ( ( ) => {
21+ sinon . restore ( ) ;
22+ } ) ;
23+
624 it ( 'should set `style.userSelect` to "none"' , ( ) => {
725 const bodyElement = { style : { } } as HTMLElement ;
826
9- setBodyStyle ( bodyElement , undefined ) ;
27+ setBodyStyle ( bodyElement , undefined , dummyDocumentElement ) ;
1028 expect ( bodyElement . style . userSelect ) . toBe ( "none" ) ;
1129 } ) ;
1230
31+ context ( "when `draggingCusrsorStyle` is undefined" , ( ) => {
32+ it ( "should not call `document.createElement`" , ( ) => {
33+ const bodyElement = { style : { } } as HTMLElement ;
34+
35+ setBodyStyle ( bodyElement , undefined , dummyDocumentElement ) ;
36+ expect ( elementCreatorMock . called ) . toBe ( false ) ;
37+ } ) ;
38+
39+ it ( "should not call `document.head.appendChild`" , ( ) => {
40+ const bodyElement = { style : { } } as HTMLElement ;
41+
42+ setBodyStyle ( bodyElement , undefined , dummyDocumentElement ) ;
43+ expect ( childAppenderSpy . called ) . toBe ( false ) ;
44+ } ) ;
45+ } ) ;
46+
1347 context ( "when `draggingCusrsorStyle` is not undefined" , ( ) => {
48+ const draggingCusrsorStyle = "dummy" ;
49+
1450 it ( 'should set `style.userSelect` to "none"' , ( ) => {
1551 const bodyElement = { style : { } } as HTMLElement ;
1652
17- setBodyStyle ( bodyElement , undefined ) ;
53+ setBodyStyle ( bodyElement , draggingCusrsorStyle , dummyDocumentElement ) ;
1854 expect ( bodyElement . style . userSelect ) . toBe ( "none" ) ;
1955 } ) ;
2056
21- it ( "should set ` style.cursor` to the string " , ( ) => {
57+ it ( "should create a style element, set attributes, and append to a document element " , ( ) => {
2258 const bodyElement = { style : { } } as HTMLElement ;
23- const draggingCusrsorStyle = "dummy" ;
2459
25- setBodyStyle ( bodyElement , draggingCusrsorStyle ) ;
26- expect ( bodyElement . style . cursor ) . toBe ( draggingCusrsorStyle ) ;
60+ setBodyStyle ( bodyElement , draggingCusrsorStyle , dummyDocumentElement ) ;
61+ expect ( elementCreatorMock . calledOnceWith ( "style" ) ) . toBe ( true ) ;
62+ expect ( dummyElement . textContent ) . toBe ( `* { cursor: ${ draggingCusrsorStyle } !important; }` ) ;
63+ expect ( elementAttributeSetterSpy . calledOnceWith ( "id" , "react-sortful-global-style" ) ) . toBe ( true ) ;
64+ expect ( childAppenderSpy . calledOnceWith ( dummyElement ) ) . toBe ( true ) ;
2765 } ) ;
2866 } ) ;
2967} ) ;
@@ -34,24 +72,46 @@ describe("clearBodyStyle", () => {
3472 Parameters < CSSStyleDeclaration [ "removeProperty" ] > ,
3573 ReturnType < CSSStyleDeclaration [ "removeProperty" ] >
3674 > ;
75+ let dummyDocumentElement : Document ;
76+ let dummyElement : HTMLElement ;
77+ let elementGetterMock : sinon . SinonStub < Parameters < Document [ "getElementById" ] > , ReturnType < Document [ "getElementById" ] > > ;
78+ let elementRemoverSpy : sinon . SinonSpy < Parameters < Element [ "remove" ] > , ReturnType < Element [ "remove" ] > > ;
3779
38- beforeAll ( ( ) => {
80+ beforeEach ( ( ) => {
3981 propertyRemoverSpy = sinon . spy ( ) as any ;
4082 bodyElement = { style : { removeProperty : propertyRemoverSpy } } as any ;
83+
84+ elementRemoverSpy = sinon . spy ( ) as any ;
85+ dummyElement = { remove : elementRemoverSpy } as any ;
86+
87+ elementGetterMock = sinon . mock ( ) . returns ( dummyElement ) as any ;
88+ dummyDocumentElement = { getElementById : elementGetterMock } as any ;
4189 } ) ;
4290 afterEach ( ( ) => {
4391 sinon . restore ( ) ;
4492 } ) ;
4593
4694 it ( 'should call `style.removeProperty` with "user-select" of `bodyElement`' , ( ) => {
47- clearBodyStyle ( bodyElement ) ;
95+ clearBodyStyle ( bodyElement , dummyDocumentElement ) ;
4896
4997 expect ( propertyRemoverSpy . calledWith ( "user-select" ) ) . toBe ( true ) ;
5098 } ) ;
5199
52- it ( 'should call `style.removeProperty` with "cursor" of `bodyElement`' , ( ) => {
53- clearBodyStyle ( bodyElement ) ;
100+ it ( "should remove a style element created by react-sortful" , ( ) => {
101+ clearBodyStyle ( bodyElement , dummyDocumentElement ) ;
102+
103+ expect ( elementGetterMock . calledOnceWith ( "react-sortful-global-style" ) ) . toBe ( true ) ;
104+ expect ( elementRemoverSpy . calledOnce ) . toBe ( true ) ;
105+ } ) ;
106+
107+ context ( "when `documentElement.getElementById` returns null" , ( ) => {
108+ beforeEach ( ( ) => {
109+ elementGetterMock = sinon . mock ( ) . returns ( null ) as any ;
110+ dummyDocumentElement = { getElementById : elementGetterMock } as any ;
111+ } ) ;
54112
55- expect ( propertyRemoverSpy . calledWith ( "cursor" ) ) . toBe ( true ) ;
113+ it ( "should not raise any errors" , ( ) => {
114+ expect ( ( ) => clearBodyStyle ( bodyElement , dummyDocumentElement ) ) . not . toThrowError ( ) ;
115+ } ) ;
56116 } ) ;
57117} ) ;
0 commit comments