diff --git a/package-lock.json b/package-lock.json index 31f714bf4..a81dd1164 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "devDependencies": { "@babel/preset-env": "^7.19.4", "@babel/preset-typescript": "^7.18.6", + "@fast-check/jest": "^1.3.0", "@ibm/plex": "^6.1.1", "@playwright/test": "^1.27.1", "@prettier/plugin-xml": "^2.2.0", @@ -76,7 +77,6 @@ "eslint-import-resolver-typescript": "^3.5.1", "eslint-plugin-fp-ts": "^0.3.2", "eslint-plugin-import": "^2.26.0", - "fast-check": "^3.2.0", "fetch-mock": "^9.11.0", "fp-ts-contrib": "^0.1.29", "glob": "^8.0.3", @@ -239,12 +239,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -266,12 +266,12 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -391,12 +391,12 @@ } }, "node_modules/@babel/helper-explode-assignable-expression/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -418,12 +418,12 @@ } }, "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -444,12 +444,12 @@ } }, "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -470,12 +470,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -496,12 +496,12 @@ } }, "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -529,12 +529,12 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -543,9 +543,9 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -555,19 +555,19 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -576,12 +576,12 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -602,12 +602,12 @@ } }, "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -643,12 +643,12 @@ } }, "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -673,12 +673,12 @@ } }, "node_modules/@babel/helper-replace-supers/node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -687,9 +687,9 @@ } }, "node_modules/@babel/helper-replace-supers/node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -699,19 +699,19 @@ } }, "node_modules/@babel/helper-replace-supers/node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -720,12 +720,12 @@ } }, "node_modules/@babel/helper-replace-supers/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -746,12 +746,12 @@ } }, "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -772,12 +772,12 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -798,12 +798,12 @@ } }, "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -854,12 +854,12 @@ } }, "node_modules/@babel/helper-wrap-function/node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -868,9 +868,9 @@ } }, "node_modules/@babel/helper-wrap-function/node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -880,19 +880,19 @@ } }, "node_modules/@babel/helper-wrap-function/node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -901,12 +901,12 @@ } }, "node_modules/@babel/helper-wrap-function/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -929,12 +929,12 @@ } }, "node_modules/@babel/helpers/node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -943,9 +943,9 @@ } }, "node_modules/@babel/helpers/node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -955,19 +955,19 @@ } }, "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -976,12 +976,12 @@ } }, "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -2225,9 +2225,9 @@ } }, "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -2237,12 +2237,12 @@ } }, "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -2654,6 +2654,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@fast-check/jest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fast-check/jest/-/jest-1.3.0.tgz", + "integrity": "sha512-LzGYYj5e6MITzCLhDrOep+PczTAOjNuzOzcZzfIzS4ajJmARXrrM5sip/0nq9Je5oa07CwD7E2y+UvDhcbZEOA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + } + ], + "dependencies": { + "fast-check": "^3.0.0" + }, + "peerDependencies": { + "@jest/globals": ">=25.5.2" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -3099,13 +3121,13 @@ } }, "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@jest/reporters/node_modules/ansi-styles": { @@ -3225,13 +3247,13 @@ } }, "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@jest/test-result": { @@ -3291,13 +3313,13 @@ } }, "node_modules/@jest/transform/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@jest/transform/node_modules/ansi-styles": { @@ -3472,9 +3494,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { "node": ">=6.0.0" @@ -3500,9 +3522,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -6801,9 +6823,9 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/@jest/types": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.1.2.tgz", - "integrity": "sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", "dev": true, "dependencies": { "@jest/schemas": "^29.0.0", @@ -6916,12 +6938,12 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/jest-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.1.2.tgz", - "integrity": "sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", "dev": true, "dependencies": { - "@jest/types": "^29.1.2", + "@jest/types": "^29.2.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -6933,13 +6955,13 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/jest-worker": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.1.2.tgz", - "integrity": "sha512-AdTZJxKjTSPHbXT/AIOjQVmoFx0LHFcVabWu0sxI7PAy7rFf8c0upyvgBKgguVXdM4vY74JdwkyD4hSmpTW8jA==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.1.2", + "jest-util": "^29.2.1", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -18100,13 +18122,13 @@ } }, "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/validate-npm-package-license": { @@ -18701,12 +18723,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18724,12 +18746,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18819,12 +18841,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18842,12 +18864,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18864,12 +18886,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18886,12 +18908,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18908,12 +18930,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18937,47 +18959,47 @@ }, "dependencies": { "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "requires": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } }, "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true }, "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -18994,12 +19016,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19025,12 +19047,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19051,47 +19073,47 @@ }, "dependencies": { "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "requires": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } }, "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true }, "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19108,12 +19130,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19130,12 +19152,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19152,12 +19174,12 @@ }, "dependencies": { "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19195,47 +19217,47 @@ }, "dependencies": { "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "requires": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } }, "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true }, "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -19254,47 +19276,47 @@ }, "dependencies": { "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", "dev": true, "requires": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.19.4", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } }, "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true }, "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", + "@babel/generator": "^7.19.6", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -20134,18 +20156,18 @@ }, "dependencies": { "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", "dev": true }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } @@ -20377,6 +20399,15 @@ } } }, + "@fast-check/jest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fast-check/jest/-/jest-1.3.0.tgz", + "integrity": "sha512-LzGYYj5e6MITzCLhDrOep+PczTAOjNuzOzcZzfIzS4ajJmARXrrM5sip/0nq9Je5oa07CwD7E2y+UvDhcbZEOA==", + "dev": true, + "requires": { + "fast-check": "^3.0.0" + } + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -20724,13 +20755,13 @@ }, "dependencies": { "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "ansi-styles": { @@ -20819,13 +20850,13 @@ }, "dependencies": { "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } } } @@ -20878,13 +20909,13 @@ }, "dependencies": { "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "ansi-styles": { @@ -21015,9 +21046,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, "@jridgewell/set-array": { @@ -21037,9 +21068,9 @@ } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "@jridgewell/trace-mapping": { @@ -23465,9 +23496,9 @@ } }, "@jest/types": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.1.2.tgz", - "integrity": "sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", "dev": true, "requires": { "@jest/schemas": "^29.0.0", @@ -23551,12 +23582,12 @@ "dev": true }, "jest-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.1.2.tgz", - "integrity": "sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", "dev": true, "requires": { - "@jest/types": "^29.1.2", + "@jest/types": "^29.2.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -23565,13 +23596,13 @@ } }, "jest-worker": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.1.2.tgz", - "integrity": "sha512-AdTZJxKjTSPHbXT/AIOjQVmoFx0LHFcVabWu0sxI7PAy7rFf8c0upyvgBKgguVXdM4vY74JdwkyD4hSmpTW8jA==", + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", "dev": true, "requires": { "@types/node": "*", - "jest-util": "^29.1.2", + "jest-util": "^29.2.1", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } @@ -31596,13 +31627,13 @@ }, "dependencies": { "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } } } diff --git a/package.json b/package.json index c1ebb2441..61a38b1e1 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "devDependencies": { "@babel/preset-env": "^7.19.4", "@babel/preset-typescript": "^7.18.6", + "@fast-check/jest": "^1.3.0", "@ibm/plex": "^6.1.1", "@playwright/test": "^1.27.1", "@prettier/plugin-xml": "^2.2.0", @@ -76,7 +77,6 @@ "eslint-import-resolver-typescript": "^3.5.1", "eslint-plugin-fp-ts": "^0.3.2", "eslint-plugin-import": "^2.26.0", - "fast-check": "^3.2.0", "fetch-mock": "^9.11.0", "fp-ts-contrib": "^0.1.29", "glob": "^8.0.3", diff --git a/test/fc.ts b/test/fc.ts index b123edf54..f7dfe03a2 100644 --- a/test/fc.ts +++ b/test/fc.ts @@ -1,8 +1,8 @@ +import { fc } from '@fast-check/jest' import { Temporal } from '@js-temporal/polyfill' import { mod11_2 } from 'cdigit' import { Doi, isDoi } from 'doi-ts' import { Request, Response } from 'express' -import * as fc from 'fast-check' import * as F from 'fetch-fp-ts' import { isNonEmpty } from 'fp-ts/Array' import { NonEmptyArray } from 'fp-ts/NonEmptyArray' @@ -26,7 +26,25 @@ import { import { NonEmptyString, isNonEmptyString } from '../src/string' import { User } from '../src/user' -export * from 'fast-check' +export { testProp as test } from '@fast-check/jest' + +export const { + anything, + array, + boolean, + constant, + constantFrom, + integer, + jsonValue, + lorem, + oneof, + option, + record, + string, + tuple, + uuid, + webUrl, +} = fc export const error = (): fc.Arbitrary => fc.string().map(error => new Error(error)) diff --git a/test/home.test.ts b/test/home.test.ts index 9b7af6fb1..00be5ecbb 100644 --- a/test/home.test.ts +++ b/test/home.test.ts @@ -5,75 +5,70 @@ import * as fc from './fc' import { runMiddleware } from './middleware' describe('home', () => { - test('home', async () => { - await fc.assert( - fc.asyncProperty( - fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), - async connection => { - const actual = await runMiddleware(_.home({}), connection)() + fc.test( + 'home', + [fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') })], + async connection => { + const actual = await runMiddleware(_.home({}), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.OK }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.OK }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) describe('looking up a DOI', () => { - test('with a preprint DOI', async () => { - await fc.assert( - fc.asyncProperty( - fc - .preprintDoi() - .chain(doi => - fc.tuple(fc.constant(doi), fc.connection({ body: fc.constant({ doi }), method: fc.constant('POST') })), - ), - async ([doi, connection]) => { - const actual = await runMiddleware(_.home({}), connection)() + fc.test( + 'with a preprint DOI', + [ + fc + .preprintDoi() + .chain(doi => + fc.tuple(fc.constant(doi), fc.connection({ body: fc.constant({ doi }), method: fc.constant('POST') })), + ), + ], + async ([doi, connection]) => { + const actual = await runMiddleware(_.home({}), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.SeeOther }, - { - type: 'setHeader', - name: 'Location', - value: `/preprints/doi-${encodeURIComponent( - doi.toLowerCase().replaceAll('-', '+').replaceAll('/', '-'), - )}`, - }, - { type: 'endResponse' }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.SeeOther }, + { + type: 'setHeader', + name: 'Location', + value: `/preprints/doi-${encodeURIComponent( + doi.toLowerCase().replaceAll('-', '+').replaceAll('/', '-'), + )}`, + }, + { type: 'endResponse' }, + ]), + ) + }, + ) - test('with a non-preprint DOI', async () => { - await fc.assert( - fc.asyncProperty( - fc.connection({ - body: fc.record({ doi: fc.oneof(fc.string(), fc.doi()) }, { withDeletedKeys: true }), - method: fc.constant('POST'), - }), - async connection => { - const actual = await runMiddleware(_.home({}), connection)() + fc.test( + 'with a non-preprint DOI', + [ + fc.connection({ + body: fc.record({ doi: fc.oneof(fc.string(), fc.doi()) }, { withDeletedKeys: true }), + method: fc.constant('POST'), + }), + ], + async connection => { + const actual = await runMiddleware(_.home({}), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.BadRequest }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.BadRequest }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) }) }) diff --git a/test/infrastructure.test.ts b/test/infrastructure.test.ts index e7ccf8cd7..acc96451d 100644 --- a/test/infrastructure.test.ts +++ b/test/infrastructure.test.ts @@ -24,1155 +24,1294 @@ import PlainDate = Temporal.PlainDate describe('infrastructure', () => { describe('getPreprint', () => { describe('when the preprint can be loaded', () => { - test('from AfricArXiv', async () => { - await fc.assert( - fc.asyncProperty(fc.doi(), fc.plainDate(), async (doi, posted) => { - const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { - body: { - status: 'ok', - 'message-type': 'work', - 'message-version': '1.0.0', - message: { - indexed: { - 'date-parts': [[2022, 4, 5]], - 'date-time': '2022-04-05T12:39:59Z', - timestamp: 1649162399284, - }, - posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, - 'group-title': 'AfricArXiv', - 'reference-count': 0, - publisher: 'Center for Open Science', - license: [ - { - start: { - 'date-parts': [[2019, 9, 10]], - 'date-time': '2019-09-10T00:00:00Z', - timestamp: 1568073600000, - }, - 'content-version': 'unspecified', - 'delay-in-days': 0, - URL: 'http://www.gnu.org/licenses/gpl-2.0.txt', - }, - ], - 'content-domain': { domain: [], 'crossmark-restriction': false }, - 'short-container-title': [], - abstract: - '

The Beninese agricultural sector suffers mainly from a lack of financing. This study, conducted on a random sample of 150 households in Parakou commune, shows that participatory financing with a counterpart in agricultural product is an alternative to financing the production of local farms. Food among the population of Parakou consists mainly of cereals, particularly maize (according to 75% of households surveyed). Non-agricultural households purchase agricultural products according to their purchasing power and the economic situation. This study confirms that people are suffering from social injustice caused by an increase in product prices caused by the agricultural financing activity of loan sharks. It should be noted that 75% of households are willing to adopt the participatory financing proposed in this article. Households are ready to buy at an average price of 12.172 XOF/Kg.

', - DOI: '10.31730/osf.io/yv9az', - type: 'posted-content', - created: { - 'date-parts': [[2019, 9, 10]], - 'date-time': '2019-09-10T12:36:21Z', - timestamp: 1568118981000, - }, - source: 'Crossref', - 'is-referenced-by-count': 0, - title: ['LE FINANCEMENT PARTICIPATIF\u00a0: UNE ALTERNATIVE AU FINANCEMENT AGRICOLE AU BENIN'], - prefix: '10.31730', - author: [ - { given: 'Abdoul kafid Chabi', family: 'TOKO KOUTOGUI', sequence: 'first', affiliation: [] }, - ], - member: '15934', - 'container-title': [], - 'original-title': [], - deposited: { + fc.test('from AfricArXiv', [fc.doi(), fc.plainDate()], async (doi, posted) => { + const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { + body: { + status: 'ok', + 'message-type': 'work', + 'message-version': '1.0.0', + message: { + indexed: { + 'date-parts': [[2022, 4, 5]], + 'date-time': '2022-04-05T12:39:59Z', + timestamp: 1649162399284, + }, + posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, + 'group-title': 'AfricArXiv', + 'reference-count': 0, + publisher: 'Center for Open Science', + license: [ + { + start: { 'date-parts': [[2019, 9, 10]], - 'date-time': '2019-09-10T12:36:22Z', - timestamp: 1568118982000, + 'date-time': '2019-09-10T00:00:00Z', + timestamp: 1568073600000, }, - score: 1, - resource: { primary: { URL: 'https://osf.io/yv9az' } }, - subtitle: [], - 'short-title': [], - issued: { 'date-parts': [[2019, 9, 10]] }, - 'references-count': 0, - URL: 'http://dx.doi.org/10.31730/osf.io/yv9az', - relation: {}, - published: { 'date-parts': [[2019, 9, 10]] }, - subtype: 'preprint', + 'content-version': 'unspecified', + 'delay-in-days': 0, + URL: 'http://www.gnu.org/licenses/gpl-2.0.txt', }, + ], + 'content-domain': { domain: [], 'crossmark-restriction': false }, + 'short-container-title': [], + abstract: + '

The Beninese agricultural sector suffers mainly from a lack of financing. This study, conducted on a random sample of 150 households in Parakou commune, shows that participatory financing with a counterpart in agricultural product is an alternative to financing the production of local farms. Food among the population of Parakou consists mainly of cereals, particularly maize (according to 75% of households surveyed). Non-agricultural households purchase agricultural products according to their purchasing power and the economic situation. This study confirms that people are suffering from social injustice caused by an increase in product prices caused by the agricultural financing activity of loan sharks. It should be noted that 75% of households are willing to adopt the participatory financing proposed in this article. Households are ready to buy at an average price of 12.172 XOF/Kg.

', + DOI: '10.31730/osf.io/yv9az', + type: 'posted-content', + created: { + 'date-parts': [[2019, 9, 10]], + 'date-time': '2019-09-10T12:36:21Z', + timestamp: 1568118981000, }, - }) + source: 'Crossref', + 'is-referenced-by-count': 0, + title: ['LE FINANCEMENT PARTICIPATIF\u00a0: UNE ALTERNATIVE AU FINANCEMENT AGRICOLE AU BENIN'], + prefix: '10.31730', + author: [{ given: 'Abdoul kafid Chabi', family: 'TOKO KOUTOGUI', sequence: 'first', affiliation: [] }], + member: '15934', + 'container-title': [], + 'original-title': [], + deposited: { + 'date-parts': [[2019, 9, 10]], + 'date-time': '2019-09-10T12:36:22Z', + timestamp: 1568118982000, + }, + score: 1, + resource: { primary: { URL: 'https://osf.io/yv9az' } }, + subtitle: [], + 'short-title': [], + issued: { 'date-parts': [[2019, 9, 10]] }, + 'references-count': 0, + URL: 'http://dx.doi.org/10.31730/osf.io/yv9az', + relation: {}, + published: { 'date-parts': [[2019, 9, 10]] }, + subtype: 'preprint', + }, + }, + }) + + const actual = await _.getPreprint(doi)({ fetch })() - const actual = await _.getPreprint(doi)({ fetch })() + expect(actual).toStrictEqual( + E.right({ + abstract: { + language: 'en', + text: expect.stringContaining('

The Beninese agricultural sector'), + }, + authors: [{ name: 'Abdoul kafid Chabi TOKO KOUTOGUI', orcid: undefined }], + id: { + type: 'africarxiv', + doi: '10.31730/osf.io/yv9az', + }, + posted, + title: { + language: 'fr', + text: expect.stringContaining('LE FINANCEMENT PARTICIPATIF'), + }, + url: new URL('https://osf.io/yv9az'), + }), + ) + }) - expect(actual).toStrictEqual( - E.right({ - abstract: { - language: 'en', - text: expect.stringContaining('

The Beninese agricultural sector'), + fc.test( + 'from bioRxiv/medRxiv', + [fc.doi(), fc.sanitisedHtml(), fc.plainDate(), fc.constantFrom('bioRxiv', 'medRxiv')], + async (doi, title, posted, server) => { + const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { + body: { + status: 'ok', + 'message-type': 'work', + 'message-version': '1.0.0', + message: { + institution: [{ name: server }], + indexed: { + 'date-parts': [[2022, 3, 30]], + 'date-time': '2022-03-30T20:22:00Z', + timestamp: 1648671720584, }, - authors: [{ name: 'Abdoul kafid Chabi TOKO KOUTOGUI', orcid: undefined }], - id: { - type: 'africarxiv', - doi: '10.31730/osf.io/yv9az', + posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, + 'group-title': 'Plant Biology', + 'reference-count': 53, + publisher: 'Cold Spring Harbor Laboratory', + 'content-domain': { domain: [], 'crossmark-restriction': false }, + 'short-container-title': [], + accepted: { 'date-parts': [[2022, 1, 14]] }, + abstract: + 'AbstractNon-photochemical quenching (NPQ) is the process that protects photosynthetic organisms from photodamage by dissipating the energy absorbed in excess as heat. In the model green alga Chlamydomonas reinhardtii, NPQ was abolished in the knock-out mutants of the pigment-protein complexes LHCSR3 and LHCBM1. However, while LHCSR3 was shown to be a pH sensor and switching to a quenched conformation at low pH, the role of LHCBM1 in NPQ has not been elucidated yet. In this work, we combine biochemical and physiological measurements to study short-term high light acclimation of npq5, the mutant lacking LHCBM1. We show that while in low light in the absence of this complex, the antenna size of PSII is smaller than in its presence, this effect is marginal in high light, implying that a reduction of the antenna is not responsible for the low NPQ. We also show that the mutant expresses LHCSR3 at the WT level in high light, indicating that the absence of this complex is also not the reason. Finally, NPQ remains low in the mutant even when the pH is artificially lowered to values that can switch LHCSR3 to the quenched conformation. It is concluded that both LHCSR3 and LHCBM1 need to be present for the induction of NPQ and that LHCBM1 is the interacting partner of LHCSR3. This interaction can either enhance the quenching capacity of LHCSR3 or connect this complex with the PSII supercomplex.', + DOI: '10.1101/2022.01.13.476201', + type: 'posted-content', + created: { + 'date-parts': [[2022, 1, 15]], + 'date-time': '2022-01-15T05:05:41Z', + timestamp: 1642223141000, }, - posted, - title: { - language: 'fr', - text: expect.stringContaining('LE FINANCEMENT PARTICIPATIF'), + source: 'Crossref', + 'is-referenced-by-count': 0, + title: [title.toString()], + prefix: '10.1101', + author: [ + { given: 'Xin', family: 'Liu', sequence: 'first', affiliation: [] }, + { + ORCID: 'http://orcid.org/0000-0001-5124-3000', + 'authenticated-orcid': false, + given: 'Wojciech', + family: 'Nawrocki', + sequence: 'additional', + affiliation: [], + }, + { + ORCID: 'http://orcid.org/0000-0003-3469-834X', + 'authenticated-orcid': false, + given: 'Roberta', + family: 'Croce', + sequence: 'additional', + affiliation: [], + }, + ], + member: '246', + reference: [ + { + key: '2022011723300405000_2022.01.13.476201v1.1', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.1607695114', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.2', + 'doi-asserted-by': 'publisher', + DOI: '10.1105/tpc.112.108274', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.3', + 'doi-asserted-by': 'crossref', + 'first-page': '44', + DOI: '10.1016/j.bbabio.2009.07.009', + 'article-title': + 'Redox and ATP control of photosynthetic cyclic electron flow in Chlamydomonas reinhardtii (I) aerobic conditions', + volume: '1797', + year: '2010', + 'journal-title': 'Biochim Biophys Acta', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.4', + 'doi-asserted-by': 'publisher', + DOI: '10.1146/annurev.arplant.59.032607.092759', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.5', + 'doi-asserted-by': 'publisher', + DOI: '10.1371/journal.pbio.1000577', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.6', + 'doi-asserted-by': 'publisher', + DOI: '10.1074/jbc.M111.304279', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.7', + 'doi-asserted-by': 'publisher', + DOI: '10.1016/j.bpj.2011.03.049', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.8', + 'doi-asserted-by': 'crossref', + unstructured: + 'Croce R (2020) Beyond \u2018seeing is believing\u2019: the antenna size of the photosystems in vivo. New Phytol', + DOI: '10.1111/nph.16758', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.9', + 'doi-asserted-by': 'crossref', + unstructured: + 'Croce R , van Amerongen H (2020) Light harvesting in oxygenic photosynthesis: Structural biology meets spectroscopy. Science 369', + DOI: '10.1126/science.aay2058', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.10', + 'doi-asserted-by': 'crossref', + 'first-page': '1548', + DOI: '10.1016/j.bbabio.2013.11.020', + 'article-title': + 'Repressible chloroplast gene expression in Chlamydomonas: a new tool for the study of the photosynthetic apparatus', + volume: '1837', + year: '2014', + 'journal-title': 'Biochim Biophys Acta', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.11', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.1605380113', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.12', + 'doi-asserted-by': 'crossref', + 'first-page': '63', + DOI: '10.1016/j.bbabio.2013.07.012', + 'article-title': + 'Light-harvesting complex II (LHCII) and its supramolecular organization in Chlamydomonas reinhardtii', + volume: '1837', + year: '2014', + 'journal-title': 'Biochim Biophys Acta', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.13', + 'doi-asserted-by': 'publisher', + DOI: '10.1111/tpj.12459', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.14', + 'doi-asserted-by': 'publisher', + DOI: '10.1105/tpc.002154', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.15', + 'doi-asserted-by': 'publisher', + DOI: '10.1186/1471-2148-10-233.', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.16', + 'doi-asserted-by': 'publisher', + DOI: '10.1111/tpj.12825', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.17', + 'doi-asserted-by': 'publisher', + DOI: '10.1038/nsmb.3068', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.18', + 'doi-asserted-by': 'publisher', + DOI: '10.1074/jbc.M111.316729', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.19', + 'doi-asserted-by': 'publisher', + DOI: '10.1093/jxb/erw462', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.20', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.54.6.1665', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.21', + 'doi-asserted-by': 'publisher', + DOI: '10.1105/tpc.114.124198', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.22', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.0501268102', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.23', + 'doi-asserted-by': 'crossref', + 'first-page': '7755', + DOI: '10.1021/acs.jpclett.0c02098', + 'article-title': + 'Photoprotective Capabilities of Light-Harvesting Complex II Trimers in the Green Alga Chlamydomonas reinhardtii', + volume: '11', + year: '2020', + 'journal-title': 'J Phys Chem Lett', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.24', + 'first-page': '1', + 'article-title': 'Chlorophyll a fluorescence induction1', + volume: '1412', + year: '1999', + 'journal-title': 'Biochim Biophys Acta', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.25', + 'doi-asserted-by': 'crossref', + 'first-page': '667', + DOI: '10.1016/j.tplants.2018.05.004', + 'article-title': 'Mechanisms of Photodamage and Protein Turnover in Photoinhibition', + volume: '23', + year: '2018', + 'journal-title': 'Trends Plant Sci', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.26', + 'doi-asserted-by': 'publisher', + DOI: '10.1038/35000131', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.27', + 'doi-asserted-by': 'publisher', + DOI: '10.1021/ja4107463', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.28', + 'doi-asserted-by': 'publisher', + DOI: '10.1126/science.1143609', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.29', + 'doi-asserted-by': 'publisher', + DOI: '10.1007/s11120-004-2079-2', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.30', + 'doi-asserted-by': 'publisher', + DOI: '10.1371/journal.pone.0119211', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.31', + 'doi-asserted-by': 'publisher', + DOI: '10.1104/pp.18.01213', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.32', + 'doi-asserted-by': 'crossref', + 'first-page': 'eabj0055', + DOI: '10.1126/sciadv.abj0055', + 'article-title': + 'Molecular origins of induction and loss of photoinhibition-related energy dissipation qI', + volume: '7', + year: '2021', + 'journal-title': 'Sci Adv', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.33', + 'doi-asserted-by': 'crossref', + 'first-page': '16031', + DOI: '10.1038/nplants.2016.31', + 'article-title': + 'State transitions redistribute rather than dissipate energy between the two photosystems in Chlamydomonas', + volume: '2', + year: '2016', + 'journal-title': 'Nat Plants', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.34', + 'doi-asserted-by': 'publisher', + DOI: '10.1111/j.1529-8817.1986.tb02497.x', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.35', + 'doi-asserted-by': 'publisher', + DOI: '10.1128/EC.00418-07', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.36', + 'doi-asserted-by': 'crossref', + 'first-page': '1177', + DOI: '10.1038/s41477-019-0526-5', + 'article-title': 'Disentangling the sites of non-photochemical quenching in vascular plants', + volume: '5', + year: '2019', + 'journal-title': 'Nat Plants', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.37', + 'doi-asserted-by': 'publisher', + DOI: '10.1105/tpc.9.8.1369', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.38', + 'doi-asserted-by': 'publisher', + DOI: '10.1016/j.pbi.2013.03.011', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.39', + 'first-page': '4622', + 'article-title': + 'Etude cinetique de la reaction photochimique liberant l\u2019oxygene au cours de la photosynthese', + volume: '258', + year: '1964', + 'journal-title': 'CR Acad. Sci', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.40', + 'doi-asserted-by': 'crossref', + 'first-page': '148038', + DOI: '10.1016/j.bbabio.2019.06.010', + 'article-title': 'Structural analysis and comparison of light-harvesting complexes I and II', + volume: '1861', + year: '2020', + 'journal-title': 'Biochim Biophys Acta Bioenerg', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.41', + 'doi-asserted-by': 'publisher', + DOI: '10.1038/nature08587', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.42', + 'doi-asserted-by': 'crossref', + unstructured: + 'Perozeni F , Stella GR , Ballottari M (2018) LHCSR Expression under HSP70/RBCS2 Promoter as a Strategy to Increase Productivity in Microalgae. Int J Mol Sci 19', + DOI: '10.3390/ijms19010155', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.43', + 'doi-asserted-by': 'publisher', + DOI: '10.1104/pp.16.01310', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.44', + 'doi-asserted-by': 'publisher', + DOI: '10.1105/tpc.112.103051', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.45', + 'doi-asserted-by': 'publisher', + DOI: '10.1104/pp.15.01935', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.46', + 'doi-asserted-by': 'publisher', + DOI: '10.1002/1873-3468.13111', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.47', + 'doi-asserted-by': 'crossref', + 'first-page': '379', + DOI: '10.1016/j.bbabio.2017.02.015', + 'article-title': + 'Interaction between the photoprotective protein LHCSR3 and C2S2 Photosystem II supercomplex in Chlamydomonas reinhardtii', + volume: '1858', + year: '2017', + 'journal-title': 'Biochim Biophys Acta Bioenerg', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.48', + 'doi-asserted-by': 'crossref', + 'first-page': '1320', + DOI: '10.1038/s41477-019-0543-4', + 'article-title': 'Structural insight into light harvesting for photosystem II in green algae', + volume: '5', + year: '2019', + 'journal-title': 'Nat Plants', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.49', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.46.1.83', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.50', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.0509952103', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.51', + 'doi-asserted-by': 'publisher', + DOI: '10.1073/pnas.1817796116', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.52', + 'doi-asserted-by': 'publisher', + DOI: '10.1016/B978-0-12-405210-9.00007-2', + }, + { + key: '2022011723300405000_2022.01.13.476201v1.53', + 'doi-asserted-by': 'crossref', + unstructured: + 'Xu P , Chukhutsina VU , Nawrocki WJ , Schansker G , Bielczynski LW , Lu Y , Karcher D , Bock R , Croce R (2020) Photosynthesis without beta-carotene. Elife 9', + DOI: '10.7554/eLife.58984', + }, + ], + 'container-title': [], + 'original-title': [], + link: [ + { + URL: 'https://syndication.highwire.org/content/doi/10.1101/2022.01.13.476201', + 'content-type': 'unspecified', + 'content-version': 'vor', + 'intended-application': 'similarity-checking', + }, + ], + deposited: { + 'date-parts': [[2022, 1, 18]], + 'date-time': '2022-01-18T07:30:32Z', + timestamp: 1642491032000, }, - url: new URL('https://osf.io/yv9az'), - }), - ) + score: 1, + resource: { primary: { URL: 'http://biorxiv.org/lookup/doi/10.1101/2022.01.13.476201' } }, + subtitle: [], + 'short-title': [], + issued: { 'date-parts': [[2022, 1, 14]] }, + 'references-count': 53, + URL: 'http://dx.doi.org/10.1101/2022.01.13.476201', + relation: {}, + published: { 'date-parts': [[2022, 1, 14]] }, + subtype: 'preprint', + }, + }, + }) + + const actual = await _.getPreprint(doi)({ fetch })() + + expect(actual).toStrictEqual( + E.right({ + abstract: { + language: 'en', + text: expect.anything(), + }, + authors: [ + { name: 'Xin Liu', orcid: undefined }, + { name: 'Wojciech Nawrocki', orcid: '0000-0001-5124-3000' }, + { name: 'Roberta Croce', orcid: '0000-0003-3469-834X' }, + ], + id: { + type: server.toLowerCase(), + doi: '10.1101/2022.01.13.476201', + }, + posted, + title: { + language: 'en', + text: title, + }, + url: new URL('https://biorxiv.org/lookup/doi/10.1101/2022.01.13.476201'), + }), + ) + }, + ) + + fc.test('from SciELO', [fc.doi(), fc.sanitisedHtml(), fc.plainDate()], async (doi, title, posted) => { + const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { + body: { + status: 'ok', + 'message-type': 'work', + 'message-version': '1.0.0', + message: { + indexed: { + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T20:13:26Z', + timestamp: 1659730406209, + }, + posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, + 'reference-count': 0, + publisher: 'FapUNIFESP (SciELO)', + license: [ + { + start: { + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T00:00:00Z', + timestamp: 1659657600000, + }, + 'content-version': 'unspecified', + 'delay-in-days': 0, + URL: 'https://creativecommons.org/licenses/by/4.0', + }, + ], + 'content-domain': { domain: [], 'crossmark-restriction': false }, + 'short-container-title': [], + abstract: + 'El art\u00edculo aborda la extensi\u00f3n universitaria como un proceso formativo en el contexto de la Universidad de Pinar del R\u00edo, Cuba. \u00a0El objetivo estuvo dirigido a su socializar un enfoque reflexivo \u2013 cr\u00edtico acerca del car\u00e1cter formativo de la extensi\u00f3n universitaria fundamentado en cuatro concepciones pedag\u00f3gicas, de las que se presentan sus ejes fundamentales. El estudio se realiz\u00f3 desde el enfoque cualitativo y como m\u00e9todos fundamentales estuvieron el dial\u00e9ctico- materialista como soporte te\u00f3rico, pr\u00e1ctico y metodol\u00f3gico de la investigaci\u00f3n, as\u00ed como te\u00f3ricos como el hist\u00f3rico\u2013l\u00f3gico en correspondencia con cada una de las concepciones dirigidas a la formaci\u00f3n para la promoci\u00f3n de lectura, la formaci\u00f3n de promotores de estilos de vida saludables, la formaci\u00f3n para la labor extensionista del estudiante y la gesti\u00f3n de la extensi\u00f3n en el Departamento Docente. Las conclusiones que se presentan, son de tipo te\u00f3rico y resultan generalizables a contextos universitarios y territoriales de manera general, permitieron corroborar el car\u00e1cter formativo del proceso, dado en la transversalidad, la profesionalizaci\u00f3n, la formaci\u00f3n integral, el Departamento docente, como c\u00e9lula de trabajo extensionista y las relaciones de jerarquizaci\u00f3n, coordinaci\u00f3n, subordinaci\u00f3n entre los diferentes actores universitarios.', + DOI: '10.1590/scielopreprints.4502', + type: 'posted-content', + created: { + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T19:53:57Z', + timestamp: 1659729237000, + }, + source: 'Crossref', + 'is-referenced-by-count': 0, + title: [title.toString()], + prefix: '10.1590', + author: [ + { + ORCID: 'http://orcid.org/0000-0003-3232-9372', + 'authenticated-orcid': false, + given: 'Yudit Rovira', + family: 'Alvarez', + sequence: 'first', + affiliation: [], + }, + { given: 'Ayl\u00e9n Rojas', family: 'Vald\u00e9s', sequence: 'additional', affiliation: [] }, + { given: 'Manuel Vento', family: 'Ruizcalder\u00f3n', sequence: 'additional', affiliation: [] }, + { given: 'Osmani Alvarez', family: 'Bencomo', sequence: 'additional', affiliation: [] }, + ], + member: '530', + 'container-title': [], + 'original-title': [], + deposited: { + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T19:55:40Z', + timestamp: 1659729340000, + }, + score: 1, + resource: { + primary: { URL: 'https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765' }, + }, + subtitle: [], + 'short-title': [], + issued: { 'date-parts': [[2022, 8, 5]] }, + 'references-count': 0, + URL: 'http://dx.doi.org/10.1590/scielopreprints.4502', + relation: {}, + published: { 'date-parts': [[2022, 8, 5]] }, + subtype: 'preprint', + }, + }, + }) + + const actual = await _.getPreprint(doi)({ fetch })() + + expect(actual).toStrictEqual( + E.right({ + abstract: { + language: 'es', + text: expect.anything(), + }, + authors: [ + { name: 'Yudit Rovira Alvarez', orcid: '0000-0003-3232-9372' }, + { name: 'Aylén Rojas Valdés', orcid: undefined }, + { name: 'Manuel Vento Ruizcalderón', orcid: undefined }, + { name: 'Osmani Alvarez Bencomo', orcid: undefined }, + ], + id: { + type: 'scielo', + doi: '10.1590/scielopreprints.4502', + }, + posted, + title: { + language: 'es', + text: title, + }, + url: new URL('https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765'), }), ) }) - test('from bioRxiv/medRxiv', async () => { - await fc.assert( - fc.asyncProperty( - fc.doi(), - fc.sanitisedHtml(), - fc.plainDate(), - fc.constantFrom('bioRxiv', 'medRxiv'), - async (doi, title, posted, server) => { - const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { + fc.test( + 'when the response is stale', + [fc.doi(), fc.sanitisedHtml(), fc.plainDate()], + async (doi, title, posted) => { + const fetch = fetchMock + .sandbox() + .getOnce( + (url, { cache }) => + url === `https://api.crossref.org/works/${encodeURIComponent(doi)}` && cache === 'force-cache', + { body: { status: 'ok', 'message-type': 'work', 'message-version': '1.0.0', message: { - institution: [{ name: server }], indexed: { - 'date-parts': [[2022, 3, 30]], - 'date-time': '2022-03-30T20:22:00Z', - timestamp: 1648671720584, + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T20:13:26Z', + timestamp: 1659730406209, }, posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, - 'group-title': 'Plant Biology', - 'reference-count': 53, - publisher: 'Cold Spring Harbor Laboratory', + 'reference-count': 0, + publisher: 'FapUNIFESP (SciELO)', + license: [ + { + start: { + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T00:00:00Z', + timestamp: 1659657600000, + }, + 'content-version': 'unspecified', + 'delay-in-days': 0, + URL: 'https://creativecommons.org/licenses/by/4.0', + }, + ], 'content-domain': { domain: [], 'crossmark-restriction': false }, 'short-container-title': [], - accepted: { 'date-parts': [[2022, 1, 14]] }, abstract: - 'AbstractNon-photochemical quenching (NPQ) is the process that protects photosynthetic organisms from photodamage by dissipating the energy absorbed in excess as heat. In the model green alga Chlamydomonas reinhardtii, NPQ was abolished in the knock-out mutants of the pigment-protein complexes LHCSR3 and LHCBM1. However, while LHCSR3 was shown to be a pH sensor and switching to a quenched conformation at low pH, the role of LHCBM1 in NPQ has not been elucidated yet. In this work, we combine biochemical and physiological measurements to study short-term high light acclimation of npq5, the mutant lacking LHCBM1. We show that while in low light in the absence of this complex, the antenna size of PSII is smaller than in its presence, this effect is marginal in high light, implying that a reduction of the antenna is not responsible for the low NPQ. We also show that the mutant expresses LHCSR3 at the WT level in high light, indicating that the absence of this complex is also not the reason. Finally, NPQ remains low in the mutant even when the pH is artificially lowered to values that can switch LHCSR3 to the quenched conformation. It is concluded that both LHCSR3 and LHCBM1 need to be present for the induction of NPQ and that LHCBM1 is the interacting partner of LHCSR3. This interaction can either enhance the quenching capacity of LHCSR3 or connect this complex with the PSII supercomplex.', - DOI: '10.1101/2022.01.13.476201', + 'El art\u00edculo aborda la extensi\u00f3n universitaria como un proceso formativo en el contexto de la Universidad de Pinar del R\u00edo, Cuba. \u00a0El objetivo estuvo dirigido a su socializar un enfoque reflexivo \u2013 cr\u00edtico acerca del car\u00e1cter formativo de la extensi\u00f3n universitaria fundamentado en cuatro concepciones pedag\u00f3gicas, de las que se presentan sus ejes fundamentales. El estudio se realiz\u00f3 desde el enfoque cualitativo y como m\u00e9todos fundamentales estuvieron el dial\u00e9ctico- materialista como soporte te\u00f3rico, pr\u00e1ctico y metodol\u00f3gico de la investigaci\u00f3n, as\u00ed como te\u00f3ricos como el hist\u00f3rico\u2013l\u00f3gico en correspondencia con cada una de las concepciones dirigidas a la formaci\u00f3n para la promoci\u00f3n de lectura, la formaci\u00f3n de promotores de estilos de vida saludables, la formaci\u00f3n para la labor extensionista del estudiante y la gesti\u00f3n de la extensi\u00f3n en el Departamento Docente. Las conclusiones que se presentan, son de tipo te\u00f3rico y resultan generalizables a contextos universitarios y territoriales de manera general, permitieron corroborar el car\u00e1cter formativo del proceso, dado en la transversalidad, la profesionalizaci\u00f3n, la formaci\u00f3n integral, el Departamento docente, como c\u00e9lula de trabajo extensionista y las relaciones de jerarquizaci\u00f3n, coordinaci\u00f3n, subordinaci\u00f3n entre los diferentes actores universitarios.', + DOI: '10.1590/scielopreprints.4502', type: 'posted-content', created: { - 'date-parts': [[2022, 1, 15]], - 'date-time': '2022-01-15T05:05:41Z', - timestamp: 1642223141000, + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T19:53:57Z', + timestamp: 1659729237000, }, source: 'Crossref', 'is-referenced-by-count': 0, title: [title.toString()], - prefix: '10.1101', + prefix: '10.1590', author: [ - { given: 'Xin', family: 'Liu', sequence: 'first', affiliation: [] }, - { - ORCID: 'http://orcid.org/0000-0001-5124-3000', - 'authenticated-orcid': false, - given: 'Wojciech', - family: 'Nawrocki', - sequence: 'additional', - affiliation: [], - }, { - ORCID: 'http://orcid.org/0000-0003-3469-834X', + ORCID: 'http://orcid.org/0000-0003-3232-9372', 'authenticated-orcid': false, - given: 'Roberta', - family: 'Croce', - sequence: 'additional', - affiliation: [], - }, - ], - member: '246', - reference: [ - { - key: '2022011723300405000_2022.01.13.476201v1.1', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.1607695114', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.2', - 'doi-asserted-by': 'publisher', - DOI: '10.1105/tpc.112.108274', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.3', - 'doi-asserted-by': 'crossref', - 'first-page': '44', - DOI: '10.1016/j.bbabio.2009.07.009', - 'article-title': - 'Redox and ATP control of photosynthetic cyclic electron flow in Chlamydomonas reinhardtii (I) aerobic conditions', - volume: '1797', - year: '2010', - 'journal-title': 'Biochim Biophys Acta', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.4', - 'doi-asserted-by': 'publisher', - DOI: '10.1146/annurev.arplant.59.032607.092759', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.5', - 'doi-asserted-by': 'publisher', - DOI: '10.1371/journal.pbio.1000577', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.6', - 'doi-asserted-by': 'publisher', - DOI: '10.1074/jbc.M111.304279', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.7', - 'doi-asserted-by': 'publisher', - DOI: '10.1016/j.bpj.2011.03.049', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.8', - 'doi-asserted-by': 'crossref', - unstructured: - 'Croce R (2020) Beyond \u2018seeing is believing\u2019: the antenna size of the photosystems in vivo. New Phytol', - DOI: '10.1111/nph.16758', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.9', - 'doi-asserted-by': 'crossref', - unstructured: - 'Croce R , van Amerongen H (2020) Light harvesting in oxygenic photosynthesis: Structural biology meets spectroscopy. Science 369', - DOI: '10.1126/science.aay2058', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.10', - 'doi-asserted-by': 'crossref', - 'first-page': '1548', - DOI: '10.1016/j.bbabio.2013.11.020', - 'article-title': - 'Repressible chloroplast gene expression in Chlamydomonas: a new tool for the study of the photosynthetic apparatus', - volume: '1837', - year: '2014', - 'journal-title': 'Biochim Biophys Acta', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.11', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.1605380113', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.12', - 'doi-asserted-by': 'crossref', - 'first-page': '63', - DOI: '10.1016/j.bbabio.2013.07.012', - 'article-title': - 'Light-harvesting complex II (LHCII) and its supramolecular organization in Chlamydomonas reinhardtii', - volume: '1837', - year: '2014', - 'journal-title': 'Biochim Biophys Acta', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.13', - 'doi-asserted-by': 'publisher', - DOI: '10.1111/tpj.12459', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.14', - 'doi-asserted-by': 'publisher', - DOI: '10.1105/tpc.002154', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.15', - 'doi-asserted-by': 'publisher', - DOI: '10.1186/1471-2148-10-233.', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.16', - 'doi-asserted-by': 'publisher', - DOI: '10.1111/tpj.12825', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.17', - 'doi-asserted-by': 'publisher', - DOI: '10.1038/nsmb.3068', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.18', - 'doi-asserted-by': 'publisher', - DOI: '10.1074/jbc.M111.316729', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.19', - 'doi-asserted-by': 'publisher', - DOI: '10.1093/jxb/erw462', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.20', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.54.6.1665', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.21', - 'doi-asserted-by': 'publisher', - DOI: '10.1105/tpc.114.124198', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.22', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.0501268102', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.23', - 'doi-asserted-by': 'crossref', - 'first-page': '7755', - DOI: '10.1021/acs.jpclett.0c02098', - 'article-title': - 'Photoprotective Capabilities of Light-Harvesting Complex II Trimers in the Green Alga Chlamydomonas reinhardtii', - volume: '11', - year: '2020', - 'journal-title': 'J Phys Chem Lett', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.24', - 'first-page': '1', - 'article-title': 'Chlorophyll a fluorescence induction1', - volume: '1412', - year: '1999', - 'journal-title': 'Biochim Biophys Acta', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.25', - 'doi-asserted-by': 'crossref', - 'first-page': '667', - DOI: '10.1016/j.tplants.2018.05.004', - 'article-title': 'Mechanisms of Photodamage and Protein Turnover in Photoinhibition', - volume: '23', - year: '2018', - 'journal-title': 'Trends Plant Sci', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.26', - 'doi-asserted-by': 'publisher', - DOI: '10.1038/35000131', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.27', - 'doi-asserted-by': 'publisher', - DOI: '10.1021/ja4107463', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.28', - 'doi-asserted-by': 'publisher', - DOI: '10.1126/science.1143609', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.29', - 'doi-asserted-by': 'publisher', - DOI: '10.1007/s11120-004-2079-2', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.30', - 'doi-asserted-by': 'publisher', - DOI: '10.1371/journal.pone.0119211', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.31', - 'doi-asserted-by': 'publisher', - DOI: '10.1104/pp.18.01213', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.32', - 'doi-asserted-by': 'crossref', - 'first-page': 'eabj0055', - DOI: '10.1126/sciadv.abj0055', - 'article-title': - 'Molecular origins of induction and loss of photoinhibition-related energy dissipation qI', - volume: '7', - year: '2021', - 'journal-title': 'Sci Adv', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.33', - 'doi-asserted-by': 'crossref', - 'first-page': '16031', - DOI: '10.1038/nplants.2016.31', - 'article-title': - 'State transitions redistribute rather than dissipate energy between the two photosystems in Chlamydomonas', - volume: '2', - year: '2016', - 'journal-title': 'Nat Plants', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.34', - 'doi-asserted-by': 'publisher', - DOI: '10.1111/j.1529-8817.1986.tb02497.x', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.35', - 'doi-asserted-by': 'publisher', - DOI: '10.1128/EC.00418-07', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.36', - 'doi-asserted-by': 'crossref', - 'first-page': '1177', - DOI: '10.1038/s41477-019-0526-5', - 'article-title': 'Disentangling the sites of non-photochemical quenching in vascular plants', - volume: '5', - year: '2019', - 'journal-title': 'Nat Plants', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.37', - 'doi-asserted-by': 'publisher', - DOI: '10.1105/tpc.9.8.1369', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.38', - 'doi-asserted-by': 'publisher', - DOI: '10.1016/j.pbi.2013.03.011', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.39', - 'first-page': '4622', - 'article-title': - 'Etude cinetique de la reaction photochimique liberant l\u2019oxygene au cours de la photosynthese', - volume: '258', - year: '1964', - 'journal-title': 'CR Acad. Sci', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.40', - 'doi-asserted-by': 'crossref', - 'first-page': '148038', - DOI: '10.1016/j.bbabio.2019.06.010', - 'article-title': 'Structural analysis and comparison of light-harvesting complexes I and II', - volume: '1861', - year: '2020', - 'journal-title': 'Biochim Biophys Acta Bioenerg', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.41', - 'doi-asserted-by': 'publisher', - DOI: '10.1038/nature08587', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.42', - 'doi-asserted-by': 'crossref', - unstructured: - 'Perozeni F , Stella GR , Ballottari M (2018) LHCSR Expression under HSP70/RBCS2 Promoter as a Strategy to Increase Productivity in Microalgae. Int J Mol Sci 19', - DOI: '10.3390/ijms19010155', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.43', - 'doi-asserted-by': 'publisher', - DOI: '10.1104/pp.16.01310', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.44', - 'doi-asserted-by': 'publisher', - DOI: '10.1105/tpc.112.103051', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.45', - 'doi-asserted-by': 'publisher', - DOI: '10.1104/pp.15.01935', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.46', - 'doi-asserted-by': 'publisher', - DOI: '10.1002/1873-3468.13111', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.47', - 'doi-asserted-by': 'crossref', - 'first-page': '379', - DOI: '10.1016/j.bbabio.2017.02.015', - 'article-title': - 'Interaction between the photoprotective protein LHCSR3 and C2S2 Photosystem II supercomplex in Chlamydomonas reinhardtii', - volume: '1858', - year: '2017', - 'journal-title': 'Biochim Biophys Acta Bioenerg', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.48', - 'doi-asserted-by': 'crossref', - 'first-page': '1320', - DOI: '10.1038/s41477-019-0543-4', - 'article-title': 'Structural insight into light harvesting for photosystem II in green algae', - volume: '5', - year: '2019', - 'journal-title': 'Nat Plants', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.49', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.46.1.83', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.50', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.0509952103', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.51', - 'doi-asserted-by': 'publisher', - DOI: '10.1073/pnas.1817796116', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.52', - 'doi-asserted-by': 'publisher', - DOI: '10.1016/B978-0-12-405210-9.00007-2', - }, - { - key: '2022011723300405000_2022.01.13.476201v1.53', - 'doi-asserted-by': 'crossref', - unstructured: - 'Xu P , Chukhutsina VU , Nawrocki WJ , Schansker G , Bielczynski LW , Lu Y , Karcher D , Bock R , Croce R (2020) Photosynthesis without beta-carotene. Elife 9', - DOI: '10.7554/eLife.58984', + given: 'Yudit Rovira', + family: 'Alvarez', + sequence: 'first', + affiliation: [], }, + { given: 'Ayl\u00e9n Rojas', family: 'Vald\u00e9s', sequence: 'additional', affiliation: [] }, + { given: 'Manuel Vento', family: 'Ruizcalder\u00f3n', sequence: 'additional', affiliation: [] }, + { given: 'Osmani Alvarez', family: 'Bencomo', sequence: 'additional', affiliation: [] }, ], + member: '530', 'container-title': [], 'original-title': [], - link: [ - { - URL: 'https://syndication.highwire.org/content/doi/10.1101/2022.01.13.476201', - 'content-type': 'unspecified', - 'content-version': 'vor', - 'intended-application': 'similarity-checking', - }, - ], deposited: { - 'date-parts': [[2022, 1, 18]], - 'date-time': '2022-01-18T07:30:32Z', - timestamp: 1642491032000, + 'date-parts': [[2022, 8, 5]], + 'date-time': '2022-08-05T19:55:40Z', + timestamp: 1659729340000, }, score: 1, - resource: { primary: { URL: 'http://biorxiv.org/lookup/doi/10.1101/2022.01.13.476201' } }, + resource: { + primary: { + URL: 'https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765', + }, + }, subtitle: [], 'short-title': [], - issued: { 'date-parts': [[2022, 1, 14]] }, - 'references-count': 53, - URL: 'http://dx.doi.org/10.1101/2022.01.13.476201', + issued: { 'date-parts': [[2022, 8, 5]] }, + 'references-count': 0, + URL: 'http://dx.doi.org/10.1590/scielopreprints.4502', relation: {}, - published: { 'date-parts': [[2022, 1, 14]] }, + published: { 'date-parts': [[2022, 8, 5]] }, subtype: 'preprint', }, }, - }) - - const actual = await _.getPreprint(doi)({ fetch })() - - expect(actual).toStrictEqual( - E.right({ - abstract: { - language: 'en', - text: expect.anything(), - }, - authors: [ - { name: 'Xin Liu', orcid: undefined }, - { name: 'Wojciech Nawrocki', orcid: '0000-0001-5124-3000' }, - { name: 'Roberta Croce', orcid: '0000-0003-3469-834X' }, - ], - id: { - type: server.toLowerCase(), - doi: '10.1101/2022.01.13.476201', - }, - posted, - title: { - language: 'en', - text: title, - }, - url: new URL('https://biorxiv.org/lookup/doi/10.1101/2022.01.13.476201'), - }), - ) - }, - ), - ) - }) - - test('from SciELO', async () => { - await fc.assert( - fc.asyncProperty(fc.doi(), fc.sanitisedHtml(), fc.plainDate(), async (doi, title, posted) => { - const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { - body: { - status: 'ok', - 'message-type': 'work', - 'message-version': '1.0.0', - message: { - indexed: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T20:13:26Z', - timestamp: 1659730406209, - }, - posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, - 'reference-count': 0, - publisher: 'FapUNIFESP (SciELO)', - license: [ - { - start: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T00:00:00Z', - timestamp: 1659657600000, - }, - 'content-version': 'unspecified', - 'delay-in-days': 0, - URL: 'https://creativecommons.org/licenses/by/4.0', - }, - ], - 'content-domain': { domain: [], 'crossmark-restriction': false }, - 'short-container-title': [], - abstract: - 'El art\u00edculo aborda la extensi\u00f3n universitaria como un proceso formativo en el contexto de la Universidad de Pinar del R\u00edo, Cuba. \u00a0El objetivo estuvo dirigido a su socializar un enfoque reflexivo \u2013 cr\u00edtico acerca del car\u00e1cter formativo de la extensi\u00f3n universitaria fundamentado en cuatro concepciones pedag\u00f3gicas, de las que se presentan sus ejes fundamentales. El estudio se realiz\u00f3 desde el enfoque cualitativo y como m\u00e9todos fundamentales estuvieron el dial\u00e9ctico- materialista como soporte te\u00f3rico, pr\u00e1ctico y metodol\u00f3gico de la investigaci\u00f3n, as\u00ed como te\u00f3ricos como el hist\u00f3rico\u2013l\u00f3gico en correspondencia con cada una de las concepciones dirigidas a la formaci\u00f3n para la promoci\u00f3n de lectura, la formaci\u00f3n de promotores de estilos de vida saludables, la formaci\u00f3n para la labor extensionista del estudiante y la gesti\u00f3n de la extensi\u00f3n en el Departamento Docente. Las conclusiones que se presentan, son de tipo te\u00f3rico y resultan generalizables a contextos universitarios y territoriales de manera general, permitieron corroborar el car\u00e1cter formativo del proceso, dado en la transversalidad, la profesionalizaci\u00f3n, la formaci\u00f3n integral, el Departamento docente, como c\u00e9lula de trabajo extensionista y las relaciones de jerarquizaci\u00f3n, coordinaci\u00f3n, subordinaci\u00f3n entre los diferentes actores universitarios.', - DOI: '10.1590/scielopreprints.4502', - type: 'posted-content', - created: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T19:53:57Z', - timestamp: 1659729237000, - }, - source: 'Crossref', - 'is-referenced-by-count': 0, - title: [title.toString()], - prefix: '10.1590', - author: [ - { - ORCID: 'http://orcid.org/0000-0003-3232-9372', - 'authenticated-orcid': false, - given: 'Yudit Rovira', - family: 'Alvarez', - sequence: 'first', - affiliation: [], - }, - { given: 'Ayl\u00e9n Rojas', family: 'Vald\u00e9s', sequence: 'additional', affiliation: [] }, - { given: 'Manuel Vento', family: 'Ruizcalder\u00f3n', sequence: 'additional', affiliation: [] }, - { given: 'Osmani Alvarez', family: 'Bencomo', sequence: 'additional', affiliation: [] }, - ], - member: '530', - 'container-title': [], - 'original-title': [], - deposited: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T19:55:40Z', - timestamp: 1659729340000, - }, - score: 1, - resource: { - primary: { URL: 'https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765' }, - }, - subtitle: [], - 'short-title': [], - issued: { 'date-parts': [[2022, 8, 5]] }, - 'references-count': 0, - URL: 'http://dx.doi.org/10.1590/scielopreprints.4502', - relation: {}, - published: { 'date-parts': [[2022, 8, 5]] }, - subtype: 'preprint', - }, + headers: { 'X-Local-Cache-Status': 'stale' }, }, - }) - - const actual = await _.getPreprint(doi)({ fetch })() - - expect(actual).toStrictEqual( - E.right({ - abstract: { - language: 'es', - text: expect.anything(), - }, - authors: [ - { name: 'Yudit Rovira Alvarez', orcid: '0000-0003-3232-9372' }, - { name: 'Aylén Rojas Valdés', orcid: undefined }, - { name: 'Manuel Vento Ruizcalderón', orcid: undefined }, - { name: 'Osmani Alvarez Bencomo', orcid: undefined }, - ], - id: { - type: 'scielo', - doi: '10.1590/scielopreprints.4502', - }, - posted, - title: { - language: 'es', - text: title, - }, - url: new URL('https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765'), - }), ) - }), - ) - }) - - test('when the response is stale', async () => { - await fc.assert( - fc.asyncProperty(fc.doi(), fc.sanitisedHtml(), fc.plainDate(), async (doi, title, posted) => { - const fetch = fetchMock - .sandbox() - .getOnce( - (url, { cache }) => - url === `https://api.crossref.org/works/${encodeURIComponent(doi)}` && cache === 'force-cache', - { - body: { - status: 'ok', - 'message-type': 'work', - 'message-version': '1.0.0', - message: { - indexed: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T20:13:26Z', - timestamp: 1659730406209, - }, - posted: { 'date-parts': [[posted.year, posted.month, posted.day]] }, - 'reference-count': 0, - publisher: 'FapUNIFESP (SciELO)', - license: [ - { - start: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T00:00:00Z', - timestamp: 1659657600000, - }, - 'content-version': 'unspecified', - 'delay-in-days': 0, - URL: 'https://creativecommons.org/licenses/by/4.0', - }, - ], - 'content-domain': { domain: [], 'crossmark-restriction': false }, - 'short-container-title': [], - abstract: - 'El art\u00edculo aborda la extensi\u00f3n universitaria como un proceso formativo en el contexto de la Universidad de Pinar del R\u00edo, Cuba. \u00a0El objetivo estuvo dirigido a su socializar un enfoque reflexivo \u2013 cr\u00edtico acerca del car\u00e1cter formativo de la extensi\u00f3n universitaria fundamentado en cuatro concepciones pedag\u00f3gicas, de las que se presentan sus ejes fundamentales. El estudio se realiz\u00f3 desde el enfoque cualitativo y como m\u00e9todos fundamentales estuvieron el dial\u00e9ctico- materialista como soporte te\u00f3rico, pr\u00e1ctico y metodol\u00f3gico de la investigaci\u00f3n, as\u00ed como te\u00f3ricos como el hist\u00f3rico\u2013l\u00f3gico en correspondencia con cada una de las concepciones dirigidas a la formaci\u00f3n para la promoci\u00f3n de lectura, la formaci\u00f3n de promotores de estilos de vida saludables, la formaci\u00f3n para la labor extensionista del estudiante y la gesti\u00f3n de la extensi\u00f3n en el Departamento Docente. Las conclusiones que se presentan, son de tipo te\u00f3rico y resultan generalizables a contextos universitarios y territoriales de manera general, permitieron corroborar el car\u00e1cter formativo del proceso, dado en la transversalidad, la profesionalizaci\u00f3n, la formaci\u00f3n integral, el Departamento docente, como c\u00e9lula de trabajo extensionista y las relaciones de jerarquizaci\u00f3n, coordinaci\u00f3n, subordinaci\u00f3n entre los diferentes actores universitarios.', - DOI: '10.1590/scielopreprints.4502', - type: 'posted-content', - created: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T19:53:57Z', - timestamp: 1659729237000, - }, - source: 'Crossref', - 'is-referenced-by-count': 0, - title: [title.toString()], - prefix: '10.1590', - author: [ - { - ORCID: 'http://orcid.org/0000-0003-3232-9372', - 'authenticated-orcid': false, - given: 'Yudit Rovira', - family: 'Alvarez', - sequence: 'first', - affiliation: [], - }, - { given: 'Ayl\u00e9n Rojas', family: 'Vald\u00e9s', sequence: 'additional', affiliation: [] }, - { given: 'Manuel Vento', family: 'Ruizcalder\u00f3n', sequence: 'additional', affiliation: [] }, - { given: 'Osmani Alvarez', family: 'Bencomo', sequence: 'additional', affiliation: [] }, - ], - member: '530', - 'container-title': [], - 'original-title': [], - deposited: { - 'date-parts': [[2022, 8, 5]], - 'date-time': '2022-08-05T19:55:40Z', - timestamp: 1659729340000, - }, - score: 1, - resource: { - primary: { - URL: 'https://preprints.scielo.org/index.php/scielo/preprint/view/4502/version/4765', - }, - }, - subtitle: [], - 'short-title': [], - issued: { 'date-parts': [[2022, 8, 5]] }, - 'references-count': 0, - URL: 'http://dx.doi.org/10.1590/scielopreprints.4502', - relation: {}, - published: { 'date-parts': [[2022, 8, 5]] }, - subtype: 'preprint', - }, - }, - headers: { 'X-Local-Cache-Status': 'stale' }, - }, - ) - .getOnce( - (url, { cache }) => - url === `https://api.crossref.org/works/${encodeURIComponent(doi)}` && cache === 'no-cache', - { throws: new Error('Network error') }, - ) + .getOnce( + (url, { cache }) => + url === `https://api.crossref.org/works/${encodeURIComponent(doi)}` && cache === 'no-cache', + { throws: new Error('Network error') }, + ) - const actual = await _.getPreprint(doi)({ fetch })() + const actual = await _.getPreprint(doi)({ fetch })() - expect(actual).toStrictEqual(E.right(expect.objectContaining({ title: { language: 'es', text: title } }))) - expect(fetch.done()).toBeTruthy() - }), - ) - }) + expect(actual).toStrictEqual(E.right(expect.objectContaining({ title: { language: 'es', text: title } }))) + expect(fetch.done()).toBeTruthy() + }, + ) }) - test('when the preprint is not found', async () => { - await fc.assert( - fc.asyncProperty(fc.doi(), async doi => { - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { status: Status.NotFound }) + fc.test('when the preprint is not found', [fc.doi()], async doi => { + const fetch = fetchMock + .sandbox() + .getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, { status: Status.NotFound }) - const actual = await _.getPreprint(doi)({ fetch })() + const actual = await _.getPreprint(doi)({ fetch })() - expect(actual).toStrictEqual(E.left('not-found')) - }), - ) + expect(actual).toStrictEqual(E.left('not-found')) }) - test('when the preprint cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty(fc.doi(), fc.record({ status: fc.integer(), body: fc.string() }), async (doi, response) => { - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, response) + fc.test( + 'when the preprint cannot be loaded', + [fc.doi(), fc.record({ status: fc.integer(), body: fc.string() })], + async (doi, response) => { + const fetch = fetchMock.sandbox().getOnce(`https://api.crossref.org/works/${encodeURIComponent(doi)}`, response) - const actual = await _.getPreprint(doi)({ fetch })() + const actual = await _.getPreprint(doi)({ fetch })() - expect(actual).toStrictEqual(E.left('unavailable')) - }), - ) - }) + expect(actual).toStrictEqual(E.left('unavailable')) + }, + ) }) describe('getPrereview', () => { - test('when the PREreview can be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), - }), - async (id, preprint) => { - const record: Record = { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ - { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, - }, - ], - id, + fc.test( + 'when the PREreview can be loaded', + [ + fc.integer(), + fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + ], + async (id, preprint) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), + self: new URL('http://example.com/file'), }, - metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', }, - } - - const getPreprintTitle = jest.fn(_ => TE.right(preprint)) - - const actual = await _.getPrereview(id)({ - fetch: fetchMock - .sandbox() - .getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }) - .getOnce( - { url: 'http://example.com/file', functionMatcher: (_, req) => req.cache === 'force-cache' }, - { body: 'Some text' }, - ), - getPreprintTitle, - })() - - expect(actual).toStrictEqual( - E.right({ - authors: [{ name: 'PREreviewer' }], - doi: '10.5281/zenodo.1061864' as Doi, - postedDate: PlainDate.from('2022-07-05'), - preprint, - text: rawHtml('Some text'), - }), - ) - expect(getPreprintTitle).toHaveBeenCalledWith(preprint.doi) + ], + resource_type: { + type: 'publication', + subtype: 'article', + }, + title: 'Title', }, - ), - ) - }) + } - test('revalidates if the PREreview is stale', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), + const getPreprintTitle = jest.fn(_ => TE.right(preprint)) + + const actual = await _.getPrereview(id)({ + fetch: fetchMock + .sandbox() + .getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }) + .getOnce( + { url: 'http://example.com/file', functionMatcher: (_, req) => req.cache === 'force-cache' }, + { body: 'Some text' }, + ), + getPreprintTitle, + })() + + expect(actual).toStrictEqual( + E.right({ + authors: [{ name: 'PREreviewer' }], + doi: '10.5281/zenodo.1061864' as Doi, + postedDate: PlainDate.from('2022-07-05'), + preprint, + text: rawHtml('Some text'), }), - async (id, preprint) => { - const record: Record = { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ - { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, - }, - ], - id, + ) + expect(getPreprintTitle).toHaveBeenCalledWith(preprint.doi) + }, + ) + + fc.test( + 'revalidates if the PREreview is stale', + [ + fc.integer(), + fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + ], + async (id, preprint) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), + self: new URL('http://example.com/file'), }, - metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', }, - } - - const fetch = fetchMock - .sandbox() - .getOnce((url, { cache }) => url === `https://zenodo.org/api/records/${id}` && cache === 'force-cache', { - body: RecordC.encode(record), - headers: { 'X-Local-Cache-Status': 'stale' }, - }) - .getOnce((url, { cache }) => url === `https://zenodo.org/api/records/${id}` && cache === 'no-cache', { - throws: new Error('Network error'), - }) - .getOnce('http://example.com/file', { body: 'Some text' }) - - const actual = await _.getPrereview(id)({ fetch, getPreprintTitle: () => TE.right(preprint) })() - - expect(actual).toStrictEqual( - E.right({ - authors: [{ name: 'PREreviewer' }], - doi: '10.5281/zenodo.1061864' as Doi, - postedDate: PlainDate.from('2022-07-05'), - preprint, - text: rawHtml('Some text'), - }), - ) - expect(fetch.done()).toBeTruthy() + ], + resource_type: { + type: 'publication', + subtype: 'article', + }, + title: 'Title', }, - ), - ) - }) - - test('when the review is not found', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - - async id => { - const actual = await _.getPrereview(id)({ - fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { - body: undefined, - status: Status.NotFound, - }), - getPreprintTitle: () => () => Promise.reject('should not be called'), - })() + } + + const fetch = fetchMock + .sandbox() + .getOnce((url, { cache }) => url === `https://zenodo.org/api/records/${id}` && cache === 'force-cache', { + body: RecordC.encode(record), + headers: { 'X-Local-Cache-Status': 'stale' }, + }) + .getOnce((url, { cache }) => url === `https://zenodo.org/api/records/${id}` && cache === 'no-cache', { + throws: new Error('Network error'), + }) + .getOnce('http://example.com/file', { body: 'Some text' }) + + const actual = await _.getPrereview(id)({ fetch, getPreprintTitle: () => TE.right(preprint) })() + + expect(actual).toStrictEqual( + E.right({ + authors: [{ name: 'PREreviewer' }], + doi: '10.5281/zenodo.1061864' as Doi, + postedDate: PlainDate.from('2022-07-05'), + preprint, + text: rawHtml('Some text'), + }), + ) + expect(fetch.done()).toBeTruthy() + }, + ) + + fc.test('when the review is not found', [fc.integer()], async id => { + const actual = await _.getPrereview(id)({ + fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { + body: undefined, + status: Status.NotFound, + }), + getPreprintTitle: () => () => Promise.reject('should not be called'), + })() - expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) - }, - ), - ) + expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) }) - test('when the review text cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), - }), - fc.integer({ min: 400, max: 599 }), - async (id, preprint, textStatus) => { - const record: Record = { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ - { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, - }, - ], - id, + fc.test( + 'when the review text cannot be loaded', + [ + fc.integer(), + fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + fc.integer({ min: 400, max: 599 }), + ], + async (id, preprint, textStatus) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), + self: new URL('http://example.com/file'), }, - metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', }, - } + ], + resource_type: { + type: 'publication', + subtype: 'article', + }, + title: 'Title', + }, + } - const actual = await _.getPrereview(id)({ - fetch: fetchMock - .sandbox() - .getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }) - .getOnce('http://example.com/file', { status: textStatus }), - getPreprintTitle: () => TE.right(preprint), - })() + const actual = await _.getPrereview(id)({ + fetch: fetchMock + .sandbox() + .getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }) + .getOnce('http://example.com/file', { status: textStatus }), + getPreprintTitle: () => TE.right(preprint), + })() + + expect(actual).toStrictEqual(E.left(expect.anything())) + }, + ) + + fc.test('when the review cannot be loaded', [fc.integer()], async id => { + const actual = await _.getPrereview(id)({ + fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { + body: undefined, + status: Status.ServiceUnavailable, + }), + getPreprintTitle: () => () => Promise.reject('should not be called'), + })() - expect(actual).toStrictEqual(E.left(expect.anything())) - }, - ), - ) + expect(actual).toStrictEqual(E.left(expect.anything())) }) - test('when the review cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), + fc.test( + 'when the preprint cannot be loaded', + [fc.integer(), fc.preprintDoi(), fc.anything()], + async (id, preprintDoi, error) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { + links: { + self: new URL('http://example.com/file'), + }, + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprintDoi, + relation: 'reviews', + resource_type: 'publication-preprint', + }, + ], + resource_type: { + type: 'publication', + subtype: 'article', + }, + title: 'Title', + }, + } - async id => { - const actual = await _.getPrereview(id)({ - fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { - body: undefined, - status: Status.ServiceUnavailable, - }), - getPreprintTitle: () => () => Promise.reject('should not be called'), - })() + const actual = await _.getPrereview(id)({ + fetch: fetchMock + .sandbox() + .getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }) + .getOnce('http://example.com/file', { body: 'Some text' }), + getPreprintTitle: () => TE.left(error), + })() + + expect(actual).toStrictEqual(E.left(error)) + }, + ) + + fc.test('when the record is not in the community', [fc.integer(), fc.preprintDoi()], async (id, preprintDoi) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { + links: { + self: new URL('http://example.com/file'), + }, + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprintDoi, + relation: 'reviews', + resource_type: 'publication-preprint', + }, + ], + resource_type: { + type: 'publication', + subtype: 'article', + }, + title: 'Title', + }, + } + + const actual = await _.getPrereview(id)({ + fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }), + getPreprintTitle: () => () => Promise.reject('should not be called'), + })() - expect(actual).toStrictEqual(E.left(expect.anything())) - }, - ), - ) + expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) }) - test('when the preprint cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty(fc.integer(), fc.preprintDoi(), fc.anything(), async (id, preprintDoi, error) => { - const record: Record = { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ + fc.test( + 'when the record does not review a preprint with a preprint DOI', + [fc.integer(), fc.oneof(fc.string(), fc.doi())], + async (id, identifier) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files: [ + { + links: { + self: new URL('http://example.com/file'), + }, + key: 'review.html', + type: 'html', + size: 58, + }, + ], + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, + scheme: 'doi', + identifier, + relation: 'reviews', + resource_type: 'publication-preprint', }, ], - id, - links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), + resource_type: { + type: 'publication', + subtype: 'article', }, - metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprintDoi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - resource_type: { - type: 'publication', - subtype: 'article', + title: 'Title', + }, + } + + const actual = await _.getPrereview(id)({ + fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }), + getPreprintTitle: () => () => Promise.reject('should not be called'), + })() + + expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) + }, + ) + + fc.test( + 'when the record does not have a HTML file', + [ + fc.integer(), + fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + fc.nonEmptyArray( + fc.record({ + links: fc.record({ + self: fc.url(), + }), + key: fc.string(), + type: fc.string().filter(type => type !== 'html'), + size: fc.integer(), + }), + { minLength: 1 }, + ), + ], + async (id, preprint, files) => { + const record: Record = { + conceptdoi: '10.5072/zenodo.1061863' as Doi, + conceptrecid: 1061863, + files, + id, + links: { + latest: new URL('http://example.com/latest'), + latest_html: new URL('http://example.com/latest_html'), + }, + metadata: { + communities: [{ id: 'prereview-reviews' }], + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: '10.5281/zenodo.1061864' as Doi, + license: { + id: 'CC-BY-4.0', + }, + publication_date: new Date('2022-07-05'), + related_identifiers: [ + { + scheme: 'doi', + identifier: preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', }, - title: 'Title', + ], + resource_type: { + type: 'publication', + subtype: 'article', }, - } - - const actual = await _.getPrereview(id)({ - fetch: fetchMock - .sandbox() - .getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }) - .getOnce('http://example.com/file', { body: 'Some text' }), - getPreprintTitle: () => TE.left(error), - })() + title: 'Title', + }, + } - expect(actual).toStrictEqual(E.left(error)) - }), - ) - }) + const actual = await _.getPrereview(id)({ + fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { + body: RecordC.encode(record), + status: Status.OK, + }), + getPreprintTitle: () => TE.right(preprint), + })() - test('when the record is not in the community', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), + expect(actual).toStrictEqual(E.left(expect.anything())) + }, + ) + }) - fc.preprintDoi(), - async (id, preprintDoi) => { - const record: Record = { + describe('getPrereviews', () => { + fc.test('when the PREreviews can be loaded', [fc.preprintId()], async preprint => { + const records: Records = { + hits: { + hits: [ + { conceptdoi: '10.5072/zenodo.1061863' as Doi, conceptrecid: 1061863, files: [ @@ -1185,12 +1324,13 @@ describe('infrastructure', () => { size: 58, }, ], - id, + id: 1061864, links: { latest: new URL('http://example.com/latest'), latest_html: new URL('http://example.com/latest_html'), }, metadata: { + communities: [{ id: 'prereview-reviews' }], creators: [{ name: 'PREreviewer' }], description: 'Description', doi: '10.5281/zenodo.1061864' as Doi, @@ -1198,44 +1338,50 @@ describe('infrastructure', () => { id: 'CC-BY-4.0', }, publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprintDoi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], resource_type: { type: 'publication', subtype: 'article', }, title: 'Title', }, - } - - const actual = await _.getPrereview(id)({ - fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }), - getPreprintTitle: () => () => Promise.reject('should not be called'), - })() - - expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) + }, + ], + }, + } + + const actual = await _.getPrereviews(preprint)({ + fetch: fetchMock.sandbox().getOnce( + { + url: 'https://zenodo.org/api/records/', + query: { + communities: 'prereview-reviews', + q: `related.identifier:"${preprint.doi}"`, + sort: 'mostrecent', + }, + }, + { + body: RecordsC.encode(records), + status: Status.OK, }, ), + })() + + expect(actual).toStrictEqual( + E.right([ + { + authors: [{ name: 'PREreviewer' }], + id: 1061864, + text: rawHtml('Description'), + }, + ]), ) }) - test('when the record does not review a preprint with a preprint DOI', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.oneof(fc.string(), fc.doi()), - - async (id, identifier) => { - const record: Record = { + fc.test('revalidates if the PREreviews are stale', [fc.preprintId()], async preprint => { + const records: Records = { + hits: { + hits: [ + { conceptdoi: '10.5072/zenodo.1061863' as Doi, conceptrecid: 1061863, files: [ @@ -1248,7 +1394,7 @@ describe('infrastructure', () => { size: 58, }, ], - id, + id: 1061864, links: { latest: new URL('http://example.com/latest'), latest_html: new URL('http://example.com/latest_html'), @@ -1262,538 +1408,325 @@ describe('infrastructure', () => { id: 'CC-BY-4.0', }, publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], resource_type: { type: 'publication', subtype: 'article', }, title: 'Title', }, - } + }, + ], + }, + } + + const fetch = fetchMock + .sandbox() + .getOnce( + (url, { cache }) => + url === + `https://zenodo.org/api/records/?${new URLSearchParams({ + communities: 'prereview-reviews', + q: `related.identifier:"${preprint.doi}"`, + size: '100', + sort: 'mostrecent', + }).toString()}` && cache === 'force-cache', + { + body: RecordsC.encode(records), + headers: { 'X-Local-Cache-Status': 'stale' }, + }, + ) + .getOnce( + (url, { cache }) => + url === + `https://zenodo.org/api/records/?${new URLSearchParams({ + communities: 'prereview-reviews', + q: `related.identifier:"${preprint.doi}"`, + size: '100', + sort: 'mostrecent', + }).toString()}` && cache === 'no-cache', + { throws: new Error('Network error') }, + ) - const actual = await _.getPrereview(id)({ - fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }), - getPreprintTitle: () => () => Promise.reject('should not be called'), - })() + const actual = await _.getPrereviews(preprint)({ fetch })() - expect(actual).toStrictEqual(E.left(expect.objectContaining({ status: Status.NotFound }))) + expect(actual).toStrictEqual( + E.right([ + { + authors: [{ name: 'PREreviewer' }], + id: 1061864, + text: rawHtml('Description'), }, - ), + ]), ) + expect(fetch.done()).toBeTruthy() }) - test('when the record does not have a HTML file', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.record({ + fc.test( + 'when the PREreviews cannot be loaded', + [fc.preprintId(), fc.integer({ min: 400, max: 599 })], + async (preprint, status) => { + const actual = await _.getPrereviews(preprint)({ + fetch: fetchMock.sandbox().getOnce( + { + url: 'https://zenodo.org/api/records/', + query: { + communities: 'prereview-reviews', + q: `related.identifier:"${preprint.doi}"`, + sort: 'mostrecent', + }, + }, + { status }, + ), + })() + + expect(actual).toStrictEqual(E.left('unavailable')) + }, + ) + }) + + describe('createRecordOnZenodo', () => { + fc.test( + 'as a public persona', + [ + fc.record({ + conduct: fc.constant('yes'), + otherAuthors: fc.array( + fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), + ), + persona: fc.constant('public'), + preprint: fc.record({ doi: fc.preprintDoi(), language: fc.languageCode(), title: fc.html(), }), - fc.nonEmptyArray( - fc.record({ - links: fc.record({ - self: fc.url(), - }), - key: fc.string(), - type: fc.string().filter(type => type !== 'html'), - size: fc.integer(), - }), - { minLength: 1 }, - ), - async (id, preprint, files) => { - const record: Record = { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files, - id, - links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), - }, - metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - related_identifiers: [ - { - scheme: 'doi', - identifier: preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', - }, - } - - const actual = await _.getPrereview(id)({ - fetch: fetchMock.sandbox().getOnce(`https://zenodo.org/api/records/${id}`, { - body: RecordC.encode(record), - status: Status.OK, - }), - getPreprintTitle: () => TE.right(preprint), - })() - - expect(actual).toStrictEqual(E.left(expect.anything())) + review: fc.html(), + user: fc.user(), + }), + fc.string(), + fc.doi(), + ], + async (newPrereview, zenodoApiKey, reviewDoi) => { + const unsubmittedDeposition: UnsubmittedDeposition = { + id: 1, + links: { + bucket: new URL('http://example.com/bucket'), + publish: new URL('http://example.com/publish'), }, - ), - ) - }) - }) - - describe('getPrereviews', () => { - test('when the PREreviews can be loaded', async () => { - await fc.assert( - fc.asyncProperty(fc.preprintId(), async preprint => { - const records: Records = { - hits: { - hits: [ - { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ - { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, - }, - ], - id: 1061864, - links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), - }, + metadata: { + creators: [{ name: newPrereview.user.name, orcid: newPrereview.user.orcid }], + description: 'Description', + prereserve_doi: { + doi: reviewDoi, + }, + title: 'Title', + upload_type: 'publication', + publication_type: 'article', + }, + state: 'unsubmitted', + submitted: false, + } + const submittedDeposition: SubmittedDeposition = { + id: 1, + metadata: { + creators: [{ name: newPrereview.user.name, orcid: newPrereview.user.orcid }], + description: 'Description', + doi: reviewDoi, + title: 'Title', + upload_type: 'publication', + publication_type: 'article', + }, + state: 'done', + submitted: true, + } + const actual = await _.createRecordOnZenodo(newPrereview)({ + fetch: fetchMock + .sandbox() + .postOnce( + { + url: 'https://zenodo.org/api/deposit/depositions', + body: { metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', + upload_type: 'publication', + publication_type: 'article', + title: plainText`PREreview of “${newPrereview.preprint.title}”`.toString(), + creators: [ + { name: newPrereview.user.name, orcid: newPrereview.user.orcid }, + ...newPrereview.otherAuthors, + ], + communities: [{ identifier: 'prereview-reviews' }], + description: newPrereview.review.toString(), + related_identifiers: [ + { + scheme: 'doi', + identifier: newPrereview.preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', + }, + ], }, }, - ], - }, - } - - const actual = await _.getPrereviews(preprint)({ - fetch: fetchMock.sandbox().getOnce( + }, { - url: 'https://zenodo.org/api/records/', - query: { - communities: 'prereview-reviews', - q: `related.identifier:"${preprint.doi}"`, - sort: 'mostrecent', - }, + body: UnsubmittedDepositionC.encode(unsubmittedDeposition), + status: Status.Created, }, + ) + .putOnce( { - body: RecordsC.encode(records), - status: Status.OK, + url: 'http://example.com/bucket/review.html', + headers: { 'Content-Type': 'text/html' }, + functionMatcher: (_, req) => req.body === newPrereview.review.toString(), }, - ), - })() - - expect(actual).toStrictEqual( - E.right([ { - authors: [{ name: 'PREreviewer' }], - id: 1061864, - text: rawHtml('Description'), + status: Status.Created, }, - ]), - ) + ) + .postOnce('http://example.com/publish', { + body: SubmittedDepositionC.encode(submittedDeposition), + status: Status.Accepted, + }), + zenodoApiKey, + })() + + expect(actual).toStrictEqual(E.right(reviewDoi)) + }, + ) + + fc.test( + 'as an pseudonym persona', + [ + fc.record({ + conduct: fc.constant('yes'), + otherAuthors: fc.array( + fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), + ), + persona: fc.constant('pseudonym'), + preprint: fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + review: fc.html(), + user: fc.user(), }), - ) - }) - - test('revalidates if the PREreviews are stale', async () => { - await fc.assert( - fc.asyncProperty(fc.preprintId(), async preprint => { - const records: Records = { - hits: { - hits: [ - { - conceptdoi: '10.5072/zenodo.1061863' as Doi, - conceptrecid: 1061863, - files: [ - { - links: { - self: new URL('http://example.com/file'), - }, - key: 'review.html', - type: 'html', - size: 58, - }, - ], - id: 1061864, - links: { - latest: new URL('http://example.com/latest'), - latest_html: new URL('http://example.com/latest_html'), - }, + fc.string(), + fc.doi(), + ], + async (newPrereview, zenodoApiKey, reviewDoi) => { + const unsubmittedDeposition: UnsubmittedDeposition = { + id: 1, + links: { + bucket: new URL('http://example.com/bucket'), + publish: new URL('http://example.com/publish'), + }, + metadata: { + creators: [{ name: 'PREreviewer' }], + description: 'Description', + prereserve_doi: { + doi: reviewDoi, + }, + title: 'Title', + upload_type: 'publication', + publication_type: 'article', + }, + state: 'unsubmitted', + submitted: false, + } + const submittedDeposition: SubmittedDeposition = { + id: 1, + metadata: { + creators: [{ name: 'PREreviewer' }], + description: 'Description', + doi: reviewDoi, + title: 'Title', + upload_type: 'publication', + publication_type: 'article', + }, + state: 'done', + submitted: true, + } + const actual = await _.createRecordOnZenodo(newPrereview)({ + fetch: fetchMock + .sandbox() + .postOnce( + { + url: 'https://zenodo.org/api/deposit/depositions', + body: { metadata: { - communities: [{ id: 'prereview-reviews' }], - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: '10.5281/zenodo.1061864' as Doi, - license: { - id: 'CC-BY-4.0', - }, - publication_date: new Date('2022-07-05'), - resource_type: { - type: 'publication', - subtype: 'article', - }, - title: 'Title', + upload_type: 'publication', + publication_type: 'article', + title: plainText`PREreview of “${newPrereview.preprint.title}”`.toString(), + creators: [{ name: newPrereview.user.pseudonym }, ...newPrereview.otherAuthors], + communities: [{ identifier: 'prereview-reviews' }], + description: newPrereview.review.toString(), + related_identifiers: [ + { + scheme: 'doi', + identifier: newPrereview.preprint.doi, + relation: 'reviews', + resource_type: 'publication-preprint', + }, + ], }, }, - ], - }, - } - - const fetch = fetchMock - .sandbox() - .getOnce( - (url, { cache }) => - url === - `https://zenodo.org/api/records/?${new URLSearchParams({ - communities: 'prereview-reviews', - q: `related.identifier:"${preprint.doi}"`, - size: '100', - sort: 'mostrecent', - }).toString()}` && cache === 'force-cache', + }, { - body: RecordsC.encode(records), - headers: { 'X-Local-Cache-Status': 'stale' }, + body: UnsubmittedDepositionC.encode(unsubmittedDeposition), + status: Status.Created, }, ) - .getOnce( - (url, { cache }) => - url === - `https://zenodo.org/api/records/?${new URLSearchParams({ - communities: 'prereview-reviews', - q: `related.identifier:"${preprint.doi}"`, - size: '100', - sort: 'mostrecent', - }).toString()}` && cache === 'no-cache', - { throws: new Error('Network error') }, - ) - - const actual = await _.getPrereviews(preprint)({ fetch })() - - expect(actual).toStrictEqual( - E.right([ + .putOnce( { - authors: [{ name: 'PREreviewer' }], - id: 1061864, - text: rawHtml('Description'), + url: 'http://example.com/bucket/review.html', + headers: { 'Content-Type': 'text/html' }, + functionMatcher: (_, req) => req.body === newPrereview.review.toString(), }, - ]), - ) - expect(fetch.done()).toBeTruthy() - }), - ) - }) - - test('when the PREreviews cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty(fc.preprintId(), fc.integer({ min: 400, max: 599 }), async (preprint, status) => { - const actual = await _.getPrereviews(preprint)({ - fetch: fetchMock.sandbox().getOnce( { - url: 'https://zenodo.org/api/records/', - query: { - communities: 'prereview-reviews', - q: `related.identifier:"${preprint.doi}"`, - sort: 'mostrecent', - }, - }, - { status }, - ), - })() - - expect(actual).toStrictEqual(E.left('unavailable')) - }), - ) - }) - }) - - describe('createRecordOnZenodo', () => { - test('as a public persona', async () => { - await fc.assert( - fc.asyncProperty( - fc.record({ - conduct: fc.constant('yes'), - otherAuthors: fc.array( - fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), - ), - persona: fc.constant('public'), - preprint: fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), - }), - review: fc.html(), - user: fc.user(), - }), - fc.string(), - fc.doi(), - async (newPrereview, zenodoApiKey, reviewDoi) => { - const unsubmittedDeposition: UnsubmittedDeposition = { - id: 1, - links: { - bucket: new URL('http://example.com/bucket'), - publish: new URL('http://example.com/publish'), - }, - metadata: { - creators: [{ name: newPrereview.user.name, orcid: newPrereview.user.orcid }], - description: 'Description', - prereserve_doi: { - doi: reviewDoi, - }, - title: 'Title', - upload_type: 'publication', - publication_type: 'article', + status: Status.Created, }, - state: 'unsubmitted', - submitted: false, - } - const submittedDeposition: SubmittedDeposition = { - id: 1, - metadata: { - creators: [{ name: newPrereview.user.name, orcid: newPrereview.user.orcid }], - description: 'Description', - doi: reviewDoi, - title: 'Title', - upload_type: 'publication', - publication_type: 'article', - }, - state: 'done', - submitted: true, - } - const actual = await _.createRecordOnZenodo(newPrereview)({ - fetch: fetchMock - .sandbox() - .postOnce( - { - url: 'https://zenodo.org/api/deposit/depositions', - body: { - metadata: { - upload_type: 'publication', - publication_type: 'article', - title: plainText`PREreview of “${newPrereview.preprint.title}”`.toString(), - creators: [ - { name: newPrereview.user.name, orcid: newPrereview.user.orcid }, - ...newPrereview.otherAuthors, - ], - communities: [{ identifier: 'prereview-reviews' }], - description: newPrereview.review.toString(), - related_identifiers: [ - { - scheme: 'doi', - identifier: newPrereview.preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - }, - }, - }, - { - body: UnsubmittedDepositionC.encode(unsubmittedDeposition), - status: Status.Created, - }, - ) - .putOnce( - { - url: 'http://example.com/bucket/review.html', - headers: { 'Content-Type': 'text/html' }, - functionMatcher: (_, req) => req.body === newPrereview.review.toString(), - }, - { - status: Status.Created, - }, - ) - .postOnce('http://example.com/publish', { - body: SubmittedDepositionC.encode(submittedDeposition), - status: Status.Accepted, - }), - zenodoApiKey, - })() - - expect(actual).toStrictEqual(E.right(reviewDoi)) - }, - ), - ) - }) - - test('as an pseudonym persona', async () => { - await fc.assert( - fc.asyncProperty( - fc.record({ - conduct: fc.constant('yes'), - otherAuthors: fc.array( - fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), - ), - persona: fc.constant('pseudonym'), - preprint: fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), - }), - review: fc.html(), - user: fc.user(), - }), - fc.string(), - fc.doi(), - async (newPrereview, zenodoApiKey, reviewDoi) => { - const unsubmittedDeposition: UnsubmittedDeposition = { - id: 1, - links: { - bucket: new URL('http://example.com/bucket'), - publish: new URL('http://example.com/publish'), - }, - metadata: { - creators: [{ name: 'PREreviewer' }], - description: 'Description', - prereserve_doi: { - doi: reviewDoi, - }, - title: 'Title', - upload_type: 'publication', - publication_type: 'article', - }, - state: 'unsubmitted', - submitted: false, - } - const submittedDeposition: SubmittedDeposition = { - id: 1, - metadata: { - creators: [{ name: 'PREreviewer' }], - description: 'Description', - doi: reviewDoi, - title: 'Title', - upload_type: 'publication', - publication_type: 'article', - }, - state: 'done', - submitted: true, - } - const actual = await _.createRecordOnZenodo(newPrereview)({ - fetch: fetchMock - .sandbox() - .postOnce( - { - url: 'https://zenodo.org/api/deposit/depositions', - body: { - metadata: { - upload_type: 'publication', - publication_type: 'article', - title: plainText`PREreview of “${newPrereview.preprint.title}”`.toString(), - creators: [{ name: newPrereview.user.pseudonym }, ...newPrereview.otherAuthors], - communities: [{ identifier: 'prereview-reviews' }], - description: newPrereview.review.toString(), - related_identifiers: [ - { - scheme: 'doi', - identifier: newPrereview.preprint.doi, - relation: 'reviews', - resource_type: 'publication-preprint', - }, - ], - }, - }, - }, - { - body: UnsubmittedDepositionC.encode(unsubmittedDeposition), - status: Status.Created, - }, - ) - .putOnce( - { - url: 'http://example.com/bucket/review.html', - headers: { 'Content-Type': 'text/html' }, - functionMatcher: (_, req) => req.body === newPrereview.review.toString(), - }, - { - status: Status.Created, - }, - ) - .postOnce('http://example.com/publish', { - body: SubmittedDepositionC.encode(submittedDeposition), - status: Status.Accepted, - }), - zenodoApiKey, - })() - - expect(actual).toStrictEqual(E.right(reviewDoi)) - }, - ), - ) - }) - - test('Zenodo is unavailable', async () => { - await fc.assert( - fc.asyncProperty( - fc.record({ - conduct: fc.constant('yes'), - otherAuthors: fc.array( - fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), - ), - persona: fc.constantFrom('public', 'pseudonym'), - preprint: fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), + ) + .postOnce('http://example.com/publish', { + body: SubmittedDepositionC.encode(submittedDeposition), + status: Status.Accepted, }), - review: fc.html(), - user: fc.user(), - }), - fc.string(), - fc.oneof( - fc.fetchResponse({ status: fc.integer({ min: 400 }) }).map(response => Promise.resolve(response)), - fc.error().map(error => Promise.reject(error)), + zenodoApiKey, + })() + + expect(actual).toStrictEqual(E.right(reviewDoi)) + }, + ) + + fc.test( + 'Zenodo is unavailable', + [ + fc.record({ + conduct: fc.constant('yes'), + otherAuthors: fc.array( + fc.record({ name: fc.nonEmptyString(), orcid: fc.orcid() }, { requiredKeys: ['name'] }), ), - async (newPrereview, zenodoApiKey, response) => { - const actual = await _.createRecordOnZenodo(newPrereview)({ - fetch: () => response, - zenodoApiKey, - })() - - expect(actual).toStrictEqual(E.left(expect.anything())) - }, + persona: fc.constantFrom('public', 'pseudonym'), + preprint: fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), + }), + review: fc.html(), + user: fc.user(), + }), + fc.string(), + fc.oneof( + fc.fetchResponse({ status: fc.integer({ min: 400 }) }).map(response => Promise.resolve(response)), + fc.error().map(error => Promise.reject(error)), ), - ) - }) + ], + async (newPrereview, zenodoApiKey, response) => { + const actual = await _.createRecordOnZenodo(newPrereview)({ + fetch: () => response, + zenodoApiKey, + })() + + expect(actual).toStrictEqual(E.left(expect.anything())) + }, + ) }) }) diff --git a/test/legacy-prereview.test.ts b/test/legacy-prereview.test.ts index 5f6a8c851..bea7c16bf 100644 --- a/test/legacy-prereview.test.ts +++ b/test/legacy-prereview.test.ts @@ -6,100 +6,93 @@ import * as fc from './fc' describe('legacy-prereview', () => { describe('getPseudonymFromLegacyPrereview', () => { - test('when the user can be decoded', async () => { - await fc.assert( - fc.asyncProperty(fc.orcid(), fc.string(), fc.string(), fc.string(), async (orcid, app, key, pseudonym) => { - const fetch = fetchMock.sandbox().getOnce( - { - url: `https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, - headers: { 'X-Api-App': app, 'X-Api-Key': key }, - }, - { - body: { - data: { - personas: [ - { - isAnonymous: true, - name: pseudonym, - }, - ], - }, + fc.test( + 'when the user can be decoded', + [fc.orcid(), fc.string(), fc.string(), fc.string()], + async (orcid, app, key, pseudonym) => { + const fetch = fetchMock.sandbox().getOnce( + { + url: `https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, + headers: { 'X-Api-App': app, 'X-Api-Key': key }, + }, + { + body: { + data: { + personas: [ + { + isAnonymous: true, + name: pseudonym, + }, + ], }, }, - ) + }, + ) - const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() + const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() - expect(actual).toStrictEqual(E.right(pseudonym)) - }), - ) - }) + expect(actual).toStrictEqual(E.right(pseudonym)) + }, + ) - test('when the work cannot be decoded', async () => { - await fc.assert( - fc.asyncProperty( - fc.orcid(), - fc.string(), - fc.string(), - fc.fetchResponse({ status: fc.constant(Status.OK) }), - async (orcid, app, key, response) => { - const fetch = fetchMock - .sandbox() - .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, response) + fc.test( + 'when the work cannot be decoded', + [fc.orcid(), fc.string(), fc.string(), fc.fetchResponse({ status: fc.constant(Status.OK) })], + async (orcid, app, key, response) => { + const fetch = fetchMock + .sandbox() + .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, response) - const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() + const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() - expect(actual).toStrictEqual(E.left(expect.anything())) - }, - ), - ) - }) + expect(actual).toStrictEqual(E.left(expect.anything())) + }, + ) - test('when the response has a 404 status code', async () => { - await fc.assert( - fc.asyncProperty(fc.orcid(), fc.string(), fc.string(), async (orcid, app, key) => { - const fetch = fetchMock - .sandbox() - .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, Status.NotFound) + fc.test( + 'when the response has a 404 status code', + [fc.orcid(), fc.string(), fc.string()], + async (orcid, app, key) => { + const fetch = fetchMock + .sandbox() + .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, Status.NotFound) - const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() + const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() - expect(actual).toStrictEqual(E.left('no-pseudonym')) - }), - ) - }) + expect(actual).toStrictEqual(E.left('no-pseudonym')) + }, + ) - test('when the response has a non-200/404 status code', async () => { - await fc.assert( - fc.asyncProperty( - fc.orcid(), - fc.string(), - fc.string(), - fc.integer({ min: 200, max: 599 }).filter(status => status !== Status.OK && status !== Status.NotFound), - async (orcid, app, key, status) => { - const fetch = fetchMock - .sandbox() - .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, status) + fc.test( + 'when the response has a non-200/404 status code', + [ + fc.orcid(), + fc.string(), + fc.string(), + fc.integer({ min: 200, max: 599 }).filter(status => status !== Status.OK && status !== Status.NotFound), + ], + async (orcid, app, key, status) => { + const fetch = fetchMock + .sandbox() + .getOnce(`https://prereview.org/api/v2/users/${encodeURIComponent(orcid)}`, status) - const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() + const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ fetch, legacyPrereviewApi: { app, key } })() - expect(actual).toStrictEqual(E.left(expect.objectContaining({ status }))) - }, - ), - ) - }) + expect(actual).toStrictEqual(E.left(expect.objectContaining({ status }))) + }, + ) - test('when fetch throws an error', async () => { - await fc.assert( - fc.asyncProperty(fc.orcid(), fc.string(), fc.string(), fc.error(), async (orcid, app, key, error) => { - const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ - fetch: () => Promise.reject(error), - legacyPrereviewApi: { app, key }, - })() + fc.test( + 'when fetch throws an error', + [fc.orcid(), fc.string(), fc.string(), fc.error()], + async (orcid, app, key, error) => { + const actual = await _.getPseudonymFromLegacyPrereview(orcid)({ + fetch: () => Promise.reject(error), + legacyPrereviewApi: { app, key }, + })() - expect(actual).toStrictEqual(E.left(error)) - }), - ) - }) + expect(actual).toStrictEqual(E.left(error)) + }, + ) }) }) diff --git a/test/log-in.test.ts b/test/log-in.test.ts index e56d1dae4..408d9e9a9 100644 --- a/test/log-in.test.ts +++ b/test/log-in.test.ts @@ -10,330 +10,324 @@ import { runMiddleware } from './middleware' describe('log-in', () => { describe('logIn', () => { - test('when there is a Referer header', async () => { - await fc.assert( - fc.asyncProperty( - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), - }), - fc - .webUrl() - .chain(referer => - fc.tuple(fc.connection({ headers: fc.constant({ Referer: referer }) }), fc.constant(referer)), - ), - async (oauth, [connection, referer]) => { - const actual = await runMiddleware(_.logIn({ oauth }), connection)() + fc.test( + 'when there is a Referer header', + [ + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc + .webUrl() + .chain(referer => + fc.tuple(fc.connection({ headers: fc.constant({ Referer: referer }) }), fc.constant(referer)), + ), + ], + async (oauth, [connection, referer]) => { + const actual = await runMiddleware(_.logIn({ oauth }), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.Found }, - { - type: 'setHeader', - name: 'Location', - value: new URL( - `?${new URLSearchParams({ - client_id: oauth.clientId, - response_type: 'code', - redirect_uri: oauth.redirectUri.href, - scope: '/authenticate', - state: referer, - }).toString()}`, - oauth.authorizeUrl, - ).href, - }, - { type: 'endResponse' }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.Found }, + { + type: 'setHeader', + name: 'Location', + value: new URL( + `?${new URLSearchParams({ + client_id: oauth.clientId, + response_type: 'code', + redirect_uri: oauth.redirectUri.href, + scope: '/authenticate', + state: referer, + }).toString()}`, + oauth.authorizeUrl, + ).href, + }, + { type: 'endResponse' }, + ]), + ) + }, + ) - test("when there isn't a Referer header", async () => { - await fc.assert( - fc.asyncProperty( - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), - }), - fc.connection(), - async (oauth, connection) => { - const actual = await runMiddleware(_.logIn({ oauth }), connection)() + fc.test( + "when there isn't a Referer header", + [ + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc.connection(), + ], + async (oauth, connection) => { + const actual = await runMiddleware(_.logIn({ oauth }), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.Found }, - { - type: 'setHeader', - name: 'Location', - value: new URL( - `?${new URLSearchParams({ - client_id: oauth.clientId, - response_type: 'code', - redirect_uri: oauth.redirectUri.href, - scope: '/authenticate', - state: '', - }).toString()}`, - oauth.authorizeUrl, - ).href, - }, - { type: 'endResponse' }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.Found }, + { + type: 'setHeader', + name: 'Location', + value: new URL( + `?${new URLSearchParams({ + client_id: oauth.clientId, + response_type: 'code', + redirect_uri: oauth.redirectUri.href, + scope: '/authenticate', + state: '', + }).toString()}`, + oauth.authorizeUrl, + ).href, + }, + { type: 'endResponse' }, + ]), + ) + }, + ) }) describe('authenticate', () => { - test('when the state contains a valid referer', async () => { - await fc.assert( - fc.asyncProperty( - fc.string(), - fc.url().chain(url => fc.tuple(fc.constant(url))), - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), - }), - fc.record({ - access_token: fc.string(), - token_type: fc.string(), - name: fc.string(), - orcid: fc.orcid(), + fc.test( + 'when the state contains a valid referer', + [ + fc.string(), + fc.url().chain(url => fc.tuple(fc.constant(url))), + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc.record({ + access_token: fc.string(), + token_type: fc.string(), + name: fc.string(), + orcid: fc.orcid(), + }), + fc.string(), + fc.string(), + fc.connection(), + ], + async (code, [referer], oauth, accessToken, pseudonym, secret, connection) => { + const sessionStore = new Keyv() + + const actual = await runMiddleware( + _.authenticate( + code, + referer.href, + )({ + fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { + status: Status.OK, + body: accessToken, + }), + getPseudonym: () => TE.right(pseudonym), + oauth, + publicUrl: new URL('/', referer), + secret, + sessionStore, }), - fc.string(), - fc.string(), - fc.connection(), - async (code, [referer], oauth, accessToken, pseudonym, secret, connection) => { - const sessionStore = new Keyv() + connection, + )() + const sessions = await all(sessionStore.iterator(undefined)) - const actual = await runMiddleware( - _.authenticate( - code, - referer.href, - )({ - fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { - status: Status.OK, - body: accessToken, - }), - getPseudonym: () => TE.right(pseudonym), - oauth, - publicUrl: new URL('/', referer), - secret, - sessionStore, - }), - connection, - )() - const sessions = await all(sessionStore.iterator(undefined)) + expect(sessions).toStrictEqual([ + [expect.anything(), { name: accessToken.name, orcid: accessToken.orcid, pseudonym }], + ]) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.Found }, + { type: 'setHeader', name: 'Location', value: referer.href }, + { + type: 'setCookie', + name: 'session', + options: expect.anything(), + value: expect.stringMatching(new RegExp(`^${sessions[0][0]}\\.`)), + }, + { type: 'endResponse' }, + ]), + ) + }, + ) - expect(sessions).toStrictEqual([ - [expect.anything(), { name: accessToken.name, orcid: accessToken.orcid, pseudonym }], - ]) - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.Found }, - { type: 'setHeader', name: 'Location', value: referer.href }, - { - type: 'setCookie', - name: 'session', - options: expect.anything(), - value: expect.stringMatching(new RegExp(`^${sessions[0][0]}\\.`)), - }, - { type: 'endResponse' }, - ]), - ) - }, - ), - ) - }) + fc.test( + 'when a pseudonym cannot be found', + [ + fc.string(), + fc.url().chain(url => fc.tuple(fc.constant(url))), + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc.record({ + access_token: fc.string(), + token_type: fc.string(), + name: fc.string(), + orcid: fc.orcid(), + }), + fc.string(), + fc.connection(), + ], + async (code, [referer], oauth, accessToken, secret, connection) => { + const sessionStore = new Keyv() - test('when a pseudonym cannot be found', async () => { - await fc.assert( - fc.asyncProperty( - fc.string(), - fc.url().chain(url => fc.tuple(fc.constant(url))), - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), + const actual = await runMiddleware( + _.authenticate( + code, + referer.href, + )({ + fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { + status: Status.OK, + body: accessToken, + }), + getPseudonym: () => TE.left('no-pseudonym'), + oauth, + publicUrl: new URL('/', referer), + secret, + sessionStore, }), - fc.record({ - access_token: fc.string(), - token_type: fc.string(), - name: fc.string(), - orcid: fc.orcid(), - }), - fc.string(), - fc.connection(), - async (code, [referer], oauth, accessToken, secret, connection) => { - const sessionStore = new Keyv() + connection, + )() + const sessions = await all(sessionStore.iterator(undefined)) - const actual = await runMiddleware( - _.authenticate( - code, - referer.href, - )({ - fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { - status: Status.OK, - body: accessToken, - }), - getPseudonym: () => TE.left('no-pseudonym'), - oauth, - publicUrl: new URL('/', referer), - secret, - sessionStore, - }), - connection, - )() - const sessions = await all(sessionStore.iterator(undefined)) + expect(sessions).toStrictEqual([]) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.Forbidden }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) - expect(sessions).toStrictEqual([]) - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.Forbidden }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + fc.test( + 'when a pseudonym cannot be retrieved', + [ + fc.string(), + fc.url().chain(url => fc.tuple(fc.constant(url))), + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc.record({ + access_token: fc.string(), + token_type: fc.string(), + name: fc.string(), + orcid: fc.orcid(), + }), + fc.anything(), + fc.string(), + fc.connection(), + ], + async (code, [referer], oauth, accessToken, error, secret, connection) => { + const sessionStore = new Keyv() - test('when a pseudonym cannot be retrieved', async () => { - await fc.assert( - fc.asyncProperty( - fc.string(), - fc.url().chain(url => fc.tuple(fc.constant(url))), - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), - }), - fc.record({ - access_token: fc.string(), - token_type: fc.string(), - name: fc.string(), - orcid: fc.orcid(), + const actual = await runMiddleware( + _.authenticate( + code, + referer.href, + )({ + fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { + status: Status.OK, + body: accessToken, + }), + getPseudonym: () => TE.left(error), + oauth, + publicUrl: new URL('/', referer), + secret, + sessionStore, }), - fc.anything(), - fc.string(), - fc.connection(), - async (code, [referer], oauth, accessToken, error, secret, connection) => { - const sessionStore = new Keyv() + connection, + )() + const sessions = await all(sessionStore.iterator(undefined)) - const actual = await runMiddleware( - _.authenticate( - code, - referer.href, - )({ - fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { - status: Status.OK, - body: accessToken, - }), - getPseudonym: () => TE.left(error), - oauth, - publicUrl: new URL('/', referer), - secret, - sessionStore, - }), - connection, - )() - const sessions = await all(sessionStore.iterator(undefined)) + expect(sessions).toStrictEqual([]) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.ServiceUnavailable }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) - expect(sessions).toStrictEqual([]) - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.ServiceUnavailable }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + fc.test( + 'when the state contains an invalid referer', + [ + fc.string(), + fc.url(), + fc.oneof(fc.webUrl(), fc.string()), + fc.record({ + authorizeUrl: fc.url(), + clientId: fc.string(), + clientSecret: fc.string(), + redirectUri: fc.url(), + tokenUrl: fc.url(), + }), + fc.record({ + access_token: fc.string(), + token_type: fc.string(), + name: fc.string(), + orcid: fc.orcid(), + }), + fc.string(), + fc.string(), + fc.connection(), + ], + async (code, publicUrl, state, oauth, accessToken, pseudonym, secret, connection) => { + const sessionStore = new Keyv() - test('when the state contains an invalid referer', async () => { - await fc.assert( - fc.asyncProperty( - fc.string(), - fc.url(), - fc.oneof(fc.webUrl(), fc.string()), - fc.record({ - authorizeUrl: fc.url(), - clientId: fc.string(), - clientSecret: fc.string(), - redirectUri: fc.url(), - tokenUrl: fc.url(), + const actual = await runMiddleware( + _.authenticate( + code, + state, + )({ + fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { + status: Status.OK, + body: accessToken, + }), + getPseudonym: () => TE.right(pseudonym), + oauth, + publicUrl, + secret, + sessionStore, }), - fc.record({ - access_token: fc.string(), - token_type: fc.string(), - name: fc.string(), - orcid: fc.orcid(), - }), - fc.string(), - fc.string(), - fc.connection(), - async (code, publicUrl, state, oauth, accessToken, pseudonym, secret, connection) => { - const sessionStore = new Keyv() - - const actual = await runMiddleware( - _.authenticate( - code, - state, - )({ - fetch: fetchMock.sandbox().postOnce(oauth.tokenUrl.href, { - status: Status.OK, - body: accessToken, - }), - getPseudonym: () => TE.right(pseudonym), - oauth, - publicUrl, - secret, - sessionStore, - }), - connection, - )() - const sessions = await all(sessionStore.iterator(undefined)) + connection, + )() + const sessions = await all(sessionStore.iterator(undefined)) - expect(sessions).toStrictEqual([ - [expect.anything(), { name: accessToken.name, orcid: accessToken.orcid, pseudonym }], - ]) - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.Found }, - { type: 'setHeader', name: 'Location', value: '/' }, - { - type: 'setCookie', - name: 'session', - options: expect.anything(), - value: expect.stringMatching(new RegExp(`^${sessions[0][0]}\\.`)), - }, - { type: 'endResponse' }, - ]), - ) - }, - ), - ) - }) + expect(sessions).toStrictEqual([ + [expect.anything(), { name: accessToken.name, orcid: accessToken.orcid, pseudonym }], + ]) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.Found }, + { type: 'setHeader', name: 'Location', value: '/' }, + { + type: 'setCookie', + name: 'session', + options: expect.anything(), + value: expect.stringMatching(new RegExp(`^${sessions[0][0]}\\.`)), + }, + { type: 'endResponse' }, + ]), + ) + }, + ) }) }) diff --git a/test/middleware.test.ts b/test/middleware.test.ts index 8b087cb87..eec7a37e2 100644 --- a/test/middleware.test.ts +++ b/test/middleware.test.ts @@ -5,53 +5,41 @@ import * as fc from './fc' import { runMiddleware } from './middleware' describe('middleware', () => { - test('seeOther', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), fc.string(), async (connection, location) => { - const actual = await runMiddleware(_.seeOther(location), connection)() + fc.test('seeOther', [fc.connection(), fc.string()], async (connection, location) => { + const actual = await runMiddleware(_.seeOther(location), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.SeeOther }, - { type: 'setHeader', name: 'Location', value: location }, - { type: 'endResponse' }, - ]), - ) - }), + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.SeeOther }, + { type: 'setHeader', name: 'Location', value: location }, + { type: 'endResponse' }, + ]), ) }) - test('notFound', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), async connection => { - const actual = await runMiddleware(_.notFound({}), connection)() + fc.test('notFound', [fc.connection()], async connection => { + const actual = await runMiddleware(_.notFound({}), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.NotFound }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }), + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.NotFound }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), ) }) - test('serviceUnavailable', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), async connection => { - const actual = await runMiddleware(_.serviceUnavailable({}), connection)() + fc.test('serviceUnavailable', [fc.connection()], async connection => { + const actual = await runMiddleware(_.serviceUnavailable({}), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.ServiceUnavailable }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }), + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.ServiceUnavailable }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), ) }) }) diff --git a/test/preprint.test.ts b/test/preprint.test.ts index 9cbc38116..8f17077fc 100644 --- a/test/preprint.test.ts +++ b/test/preprint.test.ts @@ -7,115 +7,103 @@ import { runMiddleware } from './middleware' describe('preprint', () => { describe('preprint', () => { - test('when the reviews can be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.connection(), - fc.preprint(), - fc.array( - fc.record({ - authors: fc.nonEmptyArray( - fc.record( - { - name: fc.string(), - orcid: fc.orcid(), - }, - { requiredKeys: ['name'] }, - ), + fc.test( + 'when the reviews can be loaded', + [ + fc.connection(), + fc.preprint(), + fc.array( + fc.record({ + authors: fc.nonEmptyArray( + fc.record( + { + name: fc.string(), + orcid: fc.orcid(), + }, + { requiredKeys: ['name'] }, ), - id: fc.integer(), - text: fc.html(), - }), - ), - async (connection, preprint, prereviews) => { - const getPreprint: jest.MockedFunction<_.GetPreprintEnv['getPreprint']> = jest.fn(_ => TE.right(preprint)) - const getPrereviews: jest.MockedFunction<_.GetPrereviewsEnv['getPrereviews']> = jest.fn(_ => - TE.right(prereviews), - ) - - const actual = await runMiddleware( - _.preprint(preprint.id.doi)({ getPreprint, getPrereviews }), - connection, - )() - - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.OK }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - expect(getPreprint).toHaveBeenCalledWith(preprint.id.doi) - expect(getPrereviews).toHaveBeenCalledWith(preprint.id) - }, + ), + id: fc.integer(), + text: fc.html(), + }), ), - ) - }) + ], + async (connection, preprint, prereviews) => { + const getPreprint: jest.MockedFunction<_.GetPreprintEnv['getPreprint']> = jest.fn(_ => TE.right(preprint)) + const getPrereviews: jest.MockedFunction<_.GetPrereviewsEnv['getPrereviews']> = jest.fn(_ => + TE.right(prereviews), + ) - test('when the preprint is not found', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), fc.preprintDoi(), async (connection, preprintDoi) => { - const actual = await runMiddleware( - _.preprint(preprintDoi)({ - getPreprint: () => TE.left('not-found'), - getPrereviews: () => () => Promise.reject('should not be called'), - }), - connection, - )() + const actual = await runMiddleware(_.preprint(preprint.id.doi)({ getPreprint, getPrereviews }), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.NotFound }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }), - ) - }) - - test('when the preprint is unavailable', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), fc.preprintDoi(), async (connection, preprintDoi) => { - const actual = await runMiddleware( - _.preprint(preprintDoi)({ - getPreprint: () => TE.left('unavailable'), - getPrereviews: () => () => Promise.reject('should not be called'), - }), - connection, - )() + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.OK }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + expect(getPreprint).toHaveBeenCalledWith(preprint.id.doi) + expect(getPrereviews).toHaveBeenCalledWith(preprint.id) + }, + ) - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.ServiceUnavailable }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) + fc.test('when the preprint is not found', [fc.connection(), fc.preprintDoi()], async (connection, preprintDoi) => { + const actual = await runMiddleware( + _.preprint(preprintDoi)({ + getPreprint: () => TE.left('not-found'), + getPrereviews: () => () => Promise.reject('should not be called'), }), + connection, + )() + + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.NotFound }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), ) }) - test('when the reviews cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty(fc.connection(), fc.preprint(), async (connection, preprint) => { - const actual = await runMiddleware( - _.preprint(preprint.id.doi)({ - getPreprint: () => TE.right(preprint), - getPrereviews: () => TE.left('unavailable'), - }), - connection, - )() + fc.test( + 'when the preprint is unavailable', + [fc.connection(), fc.preprintDoi()], + async (connection, preprintDoi) => { + const actual = await runMiddleware( + _.preprint(preprintDoi)({ + getPreprint: () => TE.left('unavailable'), + getPrereviews: () => () => Promise.reject('should not be called'), + }), + connection, + )() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.ServiceUnavailable }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.ServiceUnavailable }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) + + fc.test('when the reviews cannot be loaded', [fc.connection(), fc.preprint()], async (connection, preprint) => { + const actual = await runMiddleware( + _.preprint(preprint.id.doi)({ + getPreprint: () => TE.right(preprint), + getPrereviews: () => TE.left('unavailable'), }), + connection, + )() + + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.ServiceUnavailable }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), ) }) }) diff --git a/test/review.test.ts b/test/review.test.ts index 08f422ef6..b5dd24d76 100644 --- a/test/review.test.ts +++ b/test/review.test.ts @@ -7,85 +7,73 @@ import { runMiddleware } from './middleware' describe('review', () => { describe('review', () => { - test('when the review can be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), - fc.record({ - authors: fc.nonEmptyArray(fc.record({ name: fc.string(), orcid: fc.orcid() }, { requiredKeys: ['name'] })), - doi: fc.doi(), - postedDate: fc.plainDate(), - preprint: fc.record({ - doi: fc.preprintDoi(), - language: fc.languageCode(), - title: fc.html(), - }), - text: fc.html(), + fc.test( + 'when the review can be loaded', + [ + fc.integer(), + fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), + fc.record({ + authors: fc.nonEmptyArray(fc.record({ name: fc.string(), orcid: fc.orcid() }, { requiredKeys: ['name'] })), + doi: fc.doi(), + postedDate: fc.plainDate(), + preprint: fc.record({ + doi: fc.preprintDoi(), + language: fc.languageCode(), + title: fc.html(), }), - async (id, connection, prereview) => { - const getPrereview: jest.MockedFunction<_.GetPrereviewEnv['getPrereview']> = jest.fn(_ => - TE.right(prereview), - ) + text: fc.html(), + }), + ], + async (id, connection, prereview) => { + const getPrereview: jest.MockedFunction<_.GetPrereviewEnv['getPrereview']> = jest.fn(_ => TE.right(prereview)) - const actual = await runMiddleware(_.review(id)({ getPrereview }), connection)() + const actual = await runMiddleware(_.review(id)({ getPrereview }), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.OK }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - expect(getPrereview).toHaveBeenCalledWith(id) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.OK }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + expect(getPrereview).toHaveBeenCalledWith(id) + }, + ) - test('when the review is not found', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), - async (id, connection) => { - const actual = await runMiddleware( - _.review(id)({ getPrereview: () => TE.left({ status: Status.NotFound }) }), - connection, - )() + fc.test( + 'when the review is not found', + [fc.integer(), fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') })], + async (id, connection) => { + const actual = await runMiddleware( + _.review(id)({ getPrereview: () => TE.left({ status: Status.NotFound }) }), + connection, + )() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.NotFound }, - { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.NotFound }, + { type: 'setHeader', name: 'Cache-Control', value: 'no-store, must-revalidate' }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) - test('when the review cannot be loaded', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer(), - fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), - fc.anything(), - async (id, connection, error) => { - const actual = await runMiddleware(_.review(id)({ getPrereview: () => TE.left(error) }), connection)() + fc.test( + 'when the review cannot be loaded', + [fc.integer(), fc.connection({ method: fc.requestMethod().filter(method => method !== 'POST') }), fc.anything()], + async (id, connection, error) => { + const actual = await runMiddleware(_.review(id)({ getPrereview: () => TE.left(error) }), connection)() - expect(actual).toStrictEqual( - E.right([ - { type: 'setStatus', status: Status.ServiceUnavailable }, - { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, - { type: 'setBody', body: expect.anything() }, - ]), - ) - }, - ), - ) - }) + expect(actual).toStrictEqual( + E.right([ + { type: 'setStatus', status: Status.ServiceUnavailable }, + { type: 'setHeader', name: 'Content-Type', value: MediaType.textHTML }, + { type: 'setBody', body: expect.anything() }, + ]), + ) + }, + ) }) }) diff --git a/test/string.test.ts b/test/string.test.ts index 43c378197..db400f106 100644 --- a/test/string.test.ts +++ b/test/string.test.ts @@ -5,14 +5,10 @@ import * as fc from './fc' describe('string', () => { describe('NonEmptyStringC', () => { describe('decode', () => { - test('with a non-empty string', () => { - fc.assert( - fc.property(fc.string({ minLength: 1 }), string => { - const actual = _.NonEmptyStringC.decode(string) + fc.test('with a non-empty string', [fc.string({ minLength: 1 })], string => { + const actual = _.NonEmptyStringC.decode(string) - expect(actual).toStrictEqual(D.success(string)) - }), - ) + expect(actual).toStrictEqual(D.success(string)) }) test('with an empty string', () => { @@ -21,39 +17,24 @@ describe('string', () => { expect(actual).toStrictEqual(D.failure('', 'NonEmptyString')) }) - test('with a non-string', () => { - fc.assert( - fc.property( - fc.anything().filter(value => typeof value !== 'string'), - value => { - const actual = _.NonEmptyStringC.decode(value) + fc.test('with a non-string', [fc.anything().filter(value => typeof value !== 'string')], value => { + const actual = _.NonEmptyStringC.decode(value) - expect(actual).toStrictEqual(D.failure(value, 'string')) - }, - ), - ) + expect(actual).toStrictEqual(D.failure(value, 'string')) }) }) - test('encode', () => { - fc.assert( - fc.property(fc.nonEmptyString(), string => { - const actual = _.NonEmptyStringC.encode(string) + fc.test('encode', [fc.nonEmptyString()], string => { + const actual = _.NonEmptyStringC.encode(string) - expect(actual).toStrictEqual(string) - }), - ) + expect(actual).toStrictEqual(string) }) }) describe('isNonEmptyString', () => { describe('decode', () => { - test('with a non-empty string', () => { - fc.assert( - fc.property(fc.string({ minLength: 1 }), string => { - expect(_.isNonEmptyString(string)).toBe(true) - }), - ) + fc.test('with a non-empty string', [fc.string({ minLength: 1 })], string => { + expect(_.isNonEmptyString(string)).toBe(true) }) test('with an empty string', () => { diff --git a/test/time.test.ts b/test/time.test.ts index 5a1b5213d..7d81c5ffe 100644 --- a/test/time.test.ts +++ b/test/time.test.ts @@ -2,13 +2,9 @@ import * as _ from '../src/time' import * as fc from './fc' describe('time', () => { - test('renderTime', () => { - fc.assert( - fc.property(fc.plainDate(), date => { - const actual = _.renderDate(date) + fc.test('renderTime', [fc.plainDate()], date => { + const actual = _.renderDate(date) - expect(actual.toString()).toContain(`