Explorar o código

Add to globals from jsdom for frontend unit tests (#5283)

* Add to globals from JSDOM for frontend unit tests
* Fix tests

GitOrigin-RevId: 3a73477d9e4c3316ab2c9510ce3360740c3feb53
Alf Eaton %!s(int64=4) %!d(string=hai) anos
pai
achega
388d9c0f1e

+ 6 - 0
services/web/package-lock.json

@@ -6036,6 +6036,12 @@
         "chalk": "^4.0.0"
       }
     },
+    "@juggle/resize-observer": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
+      "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==",
+      "dev": true
+    },
     "@mdx-js/loader": {
       "version": "1.6.22",
       "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-1.6.22.tgz",

+ 1 - 0
services/web/package.json

@@ -180,6 +180,7 @@
   },
   "devDependencies": {
     "@babel/register": "^7.14.5",
+    "@juggle/resize-observer": "^3.3.1",
     "@storybook/addon-a11y": "^6.2.9",
     "@storybook/addon-essentials": "^6.2.9",
     "@storybook/react": "^6.2.9",

+ 12 - 17
services/web/test/frontend/bootstrap.js

@@ -8,9 +8,6 @@ require('jsdom-global')(undefined, {
   url: 'https://www.test-overleaf.com/',
 })
 
-// workaround for "keys.js in jsdom-global doesn't include AbortController"
-global.AbortController = window.AbortController
-
 const path = require('path')
 process.env.SHARELATEX_CONFIG = path.resolve(
   __dirname,
@@ -80,20 +77,18 @@ moment.updateLocale('en', {
   },
 })
 
-let inMemoryLocalStorage = {}
-Object.defineProperty(global, 'localStorage', {
-  value: {
-    // localStorage returns `null` when the item does not exist
-    getItem: key =>
-      inMemoryLocalStorage[key] !== undefined
-        ? inMemoryLocalStorage[key]
-        : null,
-    setItem: (key, value) => (inMemoryLocalStorage[key] = value),
-    clear: () => (inMemoryLocalStorage = {}),
-    removeItem: key => delete inMemoryLocalStorage[key],
-  },
-  writable: true,
-})
+// workaround for missing keys in jsdom-global's keys.js
+global.AbortController = window.AbortController
+global.MutationObserver = window.MutationObserver
+global.StorageEvent = window.StorageEvent
+global.SVGElement = window.SVGElement
+global.localStorage = window.localStorage
+global.performance = window.performance
+global.requestAnimationFrame = window.requestAnimationFrame
+global.sessionStorage = window.sessionStorage
+
+// add polyfill for ResizeObserver
+global.ResizeObserver = window.ResizeObserver = require('@juggle/resize-observer').ResizeObserver
 
 // node-fetch doesn't accept relative URL's: https://github.com/node-fetch/node-fetch/blob/master/docs/v2-LIMITS.md#known-differences
 const fetch = require('node-fetch')

+ 22 - 22
services/web/test/frontend/shared/hooks/use-persisted-state.test.js

@@ -7,9 +7,9 @@ import localStorage from '../../../../frontend/js/infrastructure/local-storage'
 
 describe('usePersistedState', function () {
   beforeEach(function () {
-    sinon.spy(global.localStorage, 'getItem')
-    sinon.spy(global.localStorage, 'removeItem')
-    sinon.spy(global.localStorage, 'setItem')
+    sinon.spy(window.Storage.prototype, 'getItem')
+    sinon.spy(window.Storage.prototype, 'removeItem')
+    sinon.spy(window.Storage.prototype, 'setItem')
   })
 
   afterEach(function () {
@@ -19,7 +19,7 @@ describe('usePersistedState', function () {
   it('reads the value from localStorage', function () {
     const key = 'test'
     localStorage.setItem(key, 'foo')
-    expect(global.localStorage.setItem).to.have.callCount(1)
+    expect(window.Storage.prototype.setItem).to.have.callCount(1)
 
     const Test = () => {
       const [value] = usePersistedState(key)
@@ -30,9 +30,9 @@ describe('usePersistedState', function () {
     render(<Test />)
     screen.getByText('foo')
 
-    expect(global.localStorage.getItem).to.have.callCount(1)
-    expect(global.localStorage.removeItem).to.have.callCount(0)
-    expect(global.localStorage.setItem).to.have.callCount(1)
+    expect(window.Storage.prototype.getItem).to.have.callCount(1)
+    expect(window.Storage.prototype.removeItem).to.have.callCount(0)
+    expect(window.Storage.prototype.setItem).to.have.callCount(1)
 
     expect(localStorage.getItem(key)).to.equal('foo')
   })
@@ -49,9 +49,9 @@ describe('usePersistedState', function () {
     render(<Test />)
     screen.getByText('foo')
 
-    expect(global.localStorage.getItem).to.have.callCount(1)
-    expect(global.localStorage.removeItem).to.have.callCount(0)
-    expect(global.localStorage.setItem).to.have.callCount(0)
+    expect(window.Storage.prototype.getItem).to.have.callCount(1)
+    expect(window.Storage.prototype.removeItem).to.have.callCount(0)
+    expect(window.Storage.prototype.setItem).to.have.callCount(0)
 
     expect(localStorage.getItem(key)).to.be.null
   })
@@ -59,7 +59,7 @@ describe('usePersistedState', function () {
   it('stores the new value in localStorage', function () {
     const key = 'test:store'
     localStorage.setItem(key, 'foo')
-    expect(global.localStorage.setItem).to.have.callCount(1)
+    expect(window.Storage.prototype.setItem).to.have.callCount(1)
 
     const Test = () => {
       const [value, setValue] = usePersistedState(key, 'bar')
@@ -75,9 +75,9 @@ describe('usePersistedState', function () {
 
     screen.getByText('baz')
 
-    expect(global.localStorage.getItem).to.have.callCount(1)
-    expect(global.localStorage.removeItem).to.have.callCount(0)
-    expect(global.localStorage.setItem).to.have.callCount(2)
+    expect(window.Storage.prototype.getItem).to.have.callCount(1)
+    expect(window.Storage.prototype.removeItem).to.have.callCount(0)
+    expect(window.Storage.prototype.setItem).to.have.callCount(2)
 
     expect(localStorage.getItem(key)).to.equal('baz')
   })
@@ -85,7 +85,7 @@ describe('usePersistedState', function () {
   it('removes the value from localStorage if it equals the default value', function () {
     const key = 'test:store-default'
     localStorage.setItem(key, 'foo')
-    expect(global.localStorage.setItem).to.have.callCount(1)
+    expect(window.Storage.prototype.setItem).to.have.callCount(1)
 
     const Test = () => {
       const [value, setValue] = usePersistedState(key, 'bar')
@@ -106,9 +106,9 @@ describe('usePersistedState', function () {
 
     screen.getByText('bar')
 
-    expect(global.localStorage.getItem).to.have.callCount(2)
-    expect(global.localStorage.removeItem).to.have.callCount(1)
-    expect(global.localStorage.setItem).to.have.callCount(2)
+    expect(window.Storage.prototype.getItem).to.have.callCount(2)
+    expect(window.Storage.prototype.removeItem).to.have.callCount(1)
+    expect(window.Storage.prototype.setItem).to.have.callCount(2)
 
     expect(localStorage.getItem(key)).to.be.null
   })
@@ -116,7 +116,7 @@ describe('usePersistedState', function () {
   it('handles function values', function () {
     const key = 'test:store'
     localStorage.setItem(key, 'foo')
-    expect(global.localStorage.setItem).to.have.callCount(1)
+    expect(window.Storage.prototype.setItem).to.have.callCount(1)
 
     const Test = () => {
       const [value, setValue] = usePersistedState(key)
@@ -132,9 +132,9 @@ describe('usePersistedState', function () {
 
     screen.getByText('foobar')
 
-    expect(global.localStorage.getItem).to.have.callCount(1)
-    expect(global.localStorage.removeItem).to.have.callCount(0)
-    expect(global.localStorage.setItem).to.have.callCount(2)
+    expect(window.Storage.prototype.getItem).to.have.callCount(1)
+    expect(window.Storage.prototype.removeItem).to.have.callCount(0)
+    expect(window.Storage.prototype.setItem).to.have.callCount(2)
 
     expect(localStorage.getItem(key)).to.equal('foobar')
   })