From 31aeb50a4449ec79415221fd2e5eedb2939fa71d Mon Sep 17 00:00:00 2001 From: Carl-Erik Kopseng Date: Fri, 11 Aug 2023 16:45:20 +0200 Subject: [PATCH 01/18] Remove the migration guides top-entry This is not being used, not being updated and is included in two other places --- docs/_includes/header.html | 1 - docs/guides/index.md | 7 ------- docs/{releases.html => releases.md} | 2 ++ 3 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 docs/guides/index.md rename docs/{releases.html => releases.md} (97%) diff --git a/docs/_includes/header.html b/docs/_includes/header.html index 67430ca00..4d6029b38 100644 --- a/docs/_includes/header.html +++ b/docs/_includes/header.html @@ -9,7 +9,6 @@ diff --git a/docs/guides/index.md b/docs/guides/index.md deleted file mode 100644 index 440ed4322..000000000 --- a/docs/guides/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: page -title: Guides -breadcrumb: guides ---- - -{% include docs/migration-guides.md %} diff --git a/docs/releases.html b/docs/releases.md similarity index 97% rename from docs/releases.html rename to docs/releases.md index 8d74b9155..2a6da4b5e 100644 --- a/docs/releases.html +++ b/docs/releases.md @@ -8,6 +8,7 @@ - /download - /download/ - /releases/download/ + - /guides ---
@@ -19,6 +20,7 @@

Changelog

You can see the full log of changes for each release on our separate changelog page.
+{% include docs/migration-guides.md %}
+
From 4700696601599f9f76cec76e4b40351e8034b12b Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:51:16 +0100 Subject: [PATCH 07/18] Prefer desired over wanted --- docs/_howto/typescript-swc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index ca1ac8370..a87d71c4b 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -21,7 +21,7 @@ All code and working setups described in this guide are on [Github][master-branc - Sinon: library for creating and injecting test doubles (stubs, mocks, spies and fakes) - Module system: CommonJS -### Wanted outcome +### Desired outcome Being able to replace exports on the dependency `./other` with a Sinon created test double in `main.ts` when running tests (see code below). From 043ef51c693bd3356a486e8872c9cb3a511de579 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:51:38 +0100 Subject: [PATCH 08/18] Remove copy-pasta artifact? --- docs/_howto/typescript-swc.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index a87d71c4b..5110334d1 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -53,7 +53,6 @@ export function main() { ```typescript export function toBeMocked() { return "I am the original function"; - ing; } ``` From ee8d54ea6bb6b9859b586cd3ff1791840e564290 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:51:54 +0100 Subject: [PATCH 09/18] Prefer configure over setup --- docs/_howto/typescript-swc.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index 5110334d1..e9b056c23 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -77,11 +77,13 @@ describe("main", () => { }); ``` -Additionally, both the `.swcrc` file used by SWC and the `tsconfig.json` file used by `ts-node` is setup to produce modules of the CommonJS form, not ES Modules. +Additionally, both the `.swcrc` file used by SWC and the `tsconfig.json` file used by `ts-node` is configured to produce modules of the CommonJS form, not ES Modules. ### Brief Analysis -The error message indicates the resulting output of transpilation is different from that of `ts-node`, as this is Sinon telling us that it is unable to do anything with the property of an object if the [property descriptor][descriptor] is essentially immutable. Let's sprinkle some debugging statements to figure out what the differences between the two tools are. First we will add these some debugging output to the beginning of the test, for instance just after `it("should mock", () => {`, to see what the state is _before_ we attempt to do any modifications: +The error message indicates the resulting output of transpilation is different from that of `ts-node`, as this is Sinon telling us that it is unable to do anything with the property of an object, when the [property descriptor][descriptor] is essentially immutable. + +Let's sprinkle some debugging statements to figure out what the differences between the two tools are. First we will add these some debugging output to the beginning of the test, for instance just after `it("should mock", () => {`, to see what the state is _before_ we attempt to do any modifications: ```javascript console.log("Other", Other); From be2f523c424fb41342b38a04500d76ce28b15fbb Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:52:43 +0100 Subject: [PATCH 10/18] Rephrase I think this might have been a Norwegian idiom :) --- docs/_howto/typescript-swc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index e9b056c23..c224409c9 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -81,9 +81,9 @@ Additionally, both the `.swcrc` file used by SWC and the `tsconfig.json` file us ### Brief Analysis -The error message indicates the resulting output of transpilation is different from that of `ts-node`, as this is Sinon telling us that it is unable to do anything with the property of an object, when the [property descriptor][descriptor] is essentially immutable. +The error message indicates the resulting output of transpilation is different from that of `ts-node`, as this is Sinon telling us that it is unable to do anything with the property of an object, when the [property descriptor][descriptor] is essentially immutable. -Let's sprinkle some debugging statements to figure out what the differences between the two tools are. First we will add these some debugging output to the beginning of the test, for instance just after `it("should mock", () => {`, to see what the state is _before_ we attempt to do any modifications: +Let us sprinkle some debugging statements to figure out what the differences between the two tools are. First we will add these some debugging output to the beginning of the test, for instance just after `it("should mock", () => {`, to see what the state is _before_ we attempt to do any modifications: ```javascript console.log("Other", Other); @@ -148,7 +148,7 @@ mocked The important difference to note about the object `Other` is that the property `toBeMocked` is a simple writable _value_ in the case of `ts-node` and a non-configurable _getter_ in the case of SWC. It being a getter is not a problem for Sinon, as we have a multitude of options for replacing those, but if `configurable` is set to `false` Sinon cannot really do anything about it. -If we take a look at +Let us take a closer look. #### Conclusion of analysis From a96010b10768ce286caf64f6e0451451b3af87a9 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:53:06 +0100 Subject: [PATCH 11/18] Prefer address over attack --- docs/_howto/typescript-swc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index c224409c9..971befbbb 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -154,11 +154,11 @@ Let us take a closer look. SWC transforms the imports on the form `import * as Other from './other'` into objects where the individual exports are exposed through immutable accessors (_getters_). -We can attack this issue in mainly 3 ways: +We can address this issue in mainly 3 ways: 1. somehow reconfigure SWC to produce different output when running tests that we can work with, either making writable values or configurable getters 2. use pure dependency injection, opening up `./other.ts` to be changed from the inside -3. attack how modules are loaded, injecting [an additional `require` "hook"](https://levelup.gitconnected.com/how-to-add-hooks-to-node-js-require-function-dee7acd12698) +3. address how modules are loaded, injecting [an additional `require` "hook"](https://levelup.gitconnected.com/how-to-add-hooks-to-node-js-require-function-dee7acd12698) # Solutions From a537bf058ccb29b46b813997cd0acbdf60741b19 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:53:38 +0100 Subject: [PATCH 12/18] Add 'It' to make sentence read a bit easier --- docs/_howto/typescript-swc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index 971befbbb..f57373b53 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -166,7 +166,7 @@ We can address this issue in mainly 3 ways: > [Working code][swc-mutable-export] -If we can just flip the `configurable` flag to `true` during transpilation, Sinon could be instructed to replace the getter. Turns out, there is a SWC _plugin_ that does just that: [swc_mut_cjs_exports](https://www.npmjs.com/package/swc_mut_cjs_exports). By installing that and adding the following under the `jsc` key in `.swcrc`, you know get a configurable property descriptor. +If we can just flip the `configurable` flag to `true` during transpilation, Sinon could be instructed to replace the getter. It turns out, there is a SWC _plugin_ that does just that: [swc_mut_cjs_exports](https://www.npmjs.com/package/swc_mut_cjs_exports). By installing that and adding the following under the `jsc` key in `.swcrc`, you know get a configurable property descriptor. ```json "experimental": { From f355ad30f4f7e257038286bbd1689dcfbad4e9d6 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:54:03 +0100 Subject: [PATCH 13/18] Reprhase --- docs/_howto/typescript-swc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index f57373b53..62b79b1d5 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -185,7 +185,7 @@ sandbox.replaceGetter(Other, "toBeMocked", () => stub) > [Working code][pure-di] -This technique works regardless of language, module systems, bundlers and tool chains, but requires slight modifications of the SUT to allow modifying it. You also do not get help from Sinon in automatically resetting state. +This technique works regardless of language, module systems, bundlers and tool chains, but requires slight modifications of the SUT to allow modifying it. Sinon cannot help with resetting state automatically in this scenario. **other.ts** From 1e1432dbb47ea368265a68c4b5a38746753728b3 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:54:20 +0100 Subject: [PATCH 14/18] Add 'js' to fenced block --- docs/_howto/typescript-swc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index 62b79b1d5..7361099f5 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -176,7 +176,7 @@ If we can just flip the `configurable` flag to `true` during transpilation, Sino A getter _is_ different from a value, so you need to change your testcode slightly to replace the getter: -``` +```js const stub = sandbox.fake.returns("mocked") sandbox.replaceGetter(Other, "toBeMocked", () => stub) ``` From b1d3c25732ffb246f614bda5c530457ab7a39e39 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:55:18 +0100 Subject: [PATCH 15/18] Remove (and its maintainers) --- docs/_howto/typescript-swc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index 7361099f5..d1aaea624 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -7,7 +7,7 @@ Sinon is a simple tool that only tries to do a few things and do them well: crea ## On Typescript -The Sinon project (and its maintainers) does not explicitly list TypeScript as a supported target environment. That does not mean Sinon will not run, just that there are so many complications that we cannot come up with guides on figuring out the details for you on every system :) Typescript is a super-set of EcmaScript (JavaScript) and can be transpiled in a wide variety of ways into EcmaScript, both by targetting different runtimes (ES5, ES2015, ES2023, etc) and module systems (CommonJS, ESM, AMD, ...). Some transpiler are closer to the what the standard TypeScript compiler produces, some are laxer in various ways and additionally they have all kinds of options to tweak the result. This is indeed complex, so before you dig yourself done in this matter, it is essential that you try to figure out what the resulting code _actually_ looks like. As you will see in this guide, adding a few sprinkles of `console.log` with the output of [`Object.getOwnPropertyDescriptor(object, propname)`][get-own] is usually sufficient to understand what is going on! +The Sinon project does not explicitly list TypeScript as a supported target environment. That does not mean Sinon will not run, just that there are so many complications that we cannot come up with guides on figuring out the details for you on every system :) Typescript is a super-set of EcmaScript (JavaScript) and can be transpiled in a wide variety of ways into EcmaScript, both by targetting different runtimes (ES5, ES2015, ES2023, etc) and module systems (CommonJS, ESM, AMD, ...). Some transpiler are closer to the what the standard TypeScript compiler produces, some are laxer in various ways and additionally they have all kinds of options to tweak the result. This is indeed complex, so before you dig yourself done in this matter, it is essential that you try to figure out what the resulting code _actually_ looks like. As you will see in this guide, adding a few sprinkles of `console.log` with the output of [`Object.getOwnPropertyDescriptor(object, propname)`][get-own] is usually sufficient to understand what is going on! All code and working setups described in this guide are on [Github][master-branch] and links to the correct branch can be found in each section. From 39ae5bebffd17ef73b734579d18e48c31f112565 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:56:45 +0100 Subject: [PATCH 16/18] Whitespace Sprinkling some whitespace makes the article read a lot easier --- docs/_howto/typescript-swc.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index d1aaea624..cb103d562 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -3,11 +3,17 @@ layout: page title: "Case study: real world dependency stubbing" --- -Sinon is a simple tool that only tries to do a few things and do them well: creating and injecting test doubles (spies, fakes, stubs) into objects. Unfortunately, in todays world of build pipelines, complex tooling, transpilers and different module systems, doing the simple thing quickly becomes difficult. This article is a detailed step-by-step guide on how one can approach the typical issues that arise and various approaches for debugging and solving them. The real-world case chosen is using Sinon along with [SWC][swc-project], running tests written in TypeScript in the [Mocha test runner][mocha] and wanting to replace dependencies in this ([SUT][sut]). The essence is that there are always _many_ approaches for achieving what you want. Some require tooling, some can get away with almost no tooling, some are general in nature (not specific to SWC for instance) and some are a blend. This means you can usually make some of these approaches work for other combinations of tooling as well, once you understand what is going on. Draw inspiration from the approach and figure out what works for you! +Sinon is a simple tool that only tries to do a few things and do them well: creating and injecting test doubles (spies, fakes, stubs) into objects. Unfortunately, in todays world of build pipelines, complex tooling, transpilers and different module systems, doing the simple thing quickly becomes difficult. + +This article is a detailed step-by-step guide on how one can approach the typical issues that arise and various approaches for debugging and solving them. The real-world case chosen is using Sinon along with [SWC][swc-project], running tests written in TypeScript in the [Mocha test runner][mocha] and wanting to replace dependencies in this ([SUT][sut]). The essence is that there are always _many_ approaches for achieving what you want. Some require tooling, some can get away with almost no tooling, some are general in nature (not specific to SWC for instance) and some are a blend. This means you can usually make some of these approaches work for other combinations of tooling as well, once you understand what is going on. Draw inspiration from the approach and figure out what works for you! ## On Typescript -The Sinon project does not explicitly list TypeScript as a supported target environment. That does not mean Sinon will not run, just that there are so many complications that we cannot come up with guides on figuring out the details for you on every system :) Typescript is a super-set of EcmaScript (JavaScript) and can be transpiled in a wide variety of ways into EcmaScript, both by targetting different runtimes (ES5, ES2015, ES2023, etc) and module systems (CommonJS, ESM, AMD, ...). Some transpiler are closer to the what the standard TypeScript compiler produces, some are laxer in various ways and additionally they have all kinds of options to tweak the result. This is indeed complex, so before you dig yourself done in this matter, it is essential that you try to figure out what the resulting code _actually_ looks like. As you will see in this guide, adding a few sprinkles of `console.log` with the output of [`Object.getOwnPropertyDescriptor(object, propname)`][get-own] is usually sufficient to understand what is going on! +The Sinon project does not explicitly list TypeScript as a supported target environment. That does not mean Sinon will not run, just that there are so many complications that we cannot come up with guides on figuring out the details for you on every system :) + +Typescript is a super-set of EcmaScript (JavaScript) and can be transpiled in a wide variety of ways into EcmaScript, both by targetting different runtimes (ES5, ES2015, ES2023, etc) and module systems (CommonJS, ESM, AMD, ...). Some transpiler are closer to the what the standard TypeScript compiler produces, some are laxer in various ways and additionally they have all kinds of options to tweak the result. This is indeed complex, so before you dig yourself done in this matter, it is essential that you try to figure out what the resulting code _actually_ looks like. + +As you will see in this guide, adding a few sprinkles of `console.log` with the output of [`Object.getOwnPropertyDescriptor(object, propname)`][get-own] is usually sufficient to understand what is going on! All code and working setups described in this guide are on [Github][master-branch] and links to the correct branch can be found in each section. From bfc39fea55966848e53960a66d01f4dc86b92775 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Thu, 28 Sep 2023 08:58:33 +0100 Subject: [PATCH 17/18] Remove newcomer In a few years, quibble will not be a newcomer anymore --- docs/_howto/link-seams-commonjs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_howto/link-seams-commonjs.md b/docs/_howto/link-seams-commonjs.md index eb689e955..6eb34d6aa 100644 --- a/docs/_howto/link-seams-commonjs.md +++ b/docs/_howto/link-seams-commonjs.md @@ -13,7 +13,7 @@ This guide targets the CommonJS module system, made popular by NodeJS. There are ## Hooking into `require` -For us to replace the underlying calls done by `require` we need a tool to hook into the process. There are many tools that can do this: rewire, proxyquire, the newcomer [Quibble][quibble], etc. This example will be using [proxyquire][proxyquire] to construct our _seams_ (i.e. replace the modules), but the actual mechanics will be very similar for the other tools. +For us to replace the underlying calls done by `require` we need a tool to hook into the process. There are many tools that can do this: rewire, proxyquire, [Quibble][quibble], etc. This example will be using [proxyquire][proxyquire] to construct our _seams_ (i.e. replace the modules), but the actual mechanics will be very similar for the other tools. Read it? From f3cb812ce203a3e4144db800bd1e3107e46ddac0 Mon Sep 17 00:00:00 2001 From: Carl-Erik Kopseng Date: Tue, 3 Oct 2023 09:52:34 +0200 Subject: [PATCH 18/18] Prettify --- docs/CONTRIBUTING.md | 1 + docs/_howto/typescript-swc.md | 4 ++-- docs/releases.md | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 383db3d90..7d4057a38 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -9,6 +9,7 @@ When you're contributing documentation changes for code in `main` branch, then d If you're contributing documentation for an existing release, then your documentation changes should go into the documentation for that release in `_releases/` folder, and possibly several of the following releases also. ### Where are all the _releases_? + All the files that used to be under `_releases` in the `main` can be found in the `releases` branch. The `main` branch now only keeps the latest version. That means, to fix the docs of published releases you need to checkout the _relases branch_ and supply a PR against that. ## Running the documentation site locally diff --git a/docs/_howto/typescript-swc.md b/docs/_howto/typescript-swc.md index cb103d562..316d8a54d 100644 --- a/docs/_howto/typescript-swc.md +++ b/docs/_howto/typescript-swc.md @@ -183,8 +183,8 @@ If we can just flip the `configurable` flag to `true` during transpilation, Sino A getter _is_ different from a value, so you need to change your testcode slightly to replace the getter: ```js -const stub = sandbox.fake.returns("mocked") -sandbox.replaceGetter(Other, "toBeMocked", () => stub) +const stub = sandbox.fake.returns("mocked"); +sandbox.replaceGetter(Other, "toBeMocked", () => stub); ``` ## Use pure dependency injection diff --git a/docs/releases.md b/docs/releases.md index 911a9eff7..2597e2e7a 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -18,6 +18,7 @@ redirect_from:

Changelog

You can see the full log of changes for each release on our separate changelog page. +
{% include docs/migration-guides.md %}