From 71097463d75eab7ec2f98e7c11b20864370afd04 Mon Sep 17 00:00:00 2001
From: Colum Ferry <cferry09@gmail.com>
Date: Wed, 19 Apr 2023 11:22:02 +0100
Subject: [PATCH] feat(angular): add migration to remove karma generator
 defaults

---
 packages/angular/migrations.json              |   6 +
 .../remove-karma-defaults.spec.ts             | 195 ++++++++++++++++++
 .../update-16-0-0/remove-karma-defaults.ts    |  83 ++++++++
 3 files changed, 284 insertions(+)
 create mode 100644 packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.spec.ts
 create mode 100644 packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.ts

diff --git a/packages/angular/migrations.json b/packages/angular/migrations.json
index 9a0a545d414aa..6428c9e93e0ae 100644
--- a/packages/angular/migrations.json
+++ b/packages/angular/migrations.json
@@ -176,6 +176,12 @@
       "version": "16.0.0-beta.1",
       "description": "Replace @nrwl/angular with @nx/angular",
       "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
+    },
+    "remove-karma-defaults-from-generators": {
+      "cli": "nx",
+      "version": "16.0.0-beta.6",
+      "description": "Remove karma as default unitTestRunner from nxJson and project configurations",
+      "implementation": "./src/migrations/update-16-0-0/remove-karma-defaults"
     }
   },
   "packageJsonUpdates": {
diff --git a/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.spec.ts b/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.spec.ts
new file mode 100644
index 0000000000000..4cfa3e0c0fcad
--- /dev/null
+++ b/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.spec.ts
@@ -0,0 +1,195 @@
+import {
+  addProjectConfiguration,
+  readNxJson,
+  readProjectConfiguration,
+  updateNxJson,
+} from '@nx/devkit';
+import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
+import removeKarmaDefaults from './remove-karma-defaults';
+
+describe('removeKarmaDefaults', () => {
+  it('should remove karma as default unit test runner from nx.json when exists', async () => {
+    // ARRANGE
+    const tree = createTreeWithEmptyWorkspace();
+
+    const nxJson = readNxJson(tree);
+    nxJson.generators = {
+      '@nrwl/angular:application': {
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:library': {
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:host': {
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:remote': {
+        unitTestRunner: 'karma',
+      },
+    };
+    updateNxJson(tree, nxJson);
+
+    // ACT
+    await removeKarmaDefaults(tree);
+
+    // ASSERT
+    expect(readNxJson(tree).generators).toMatchInlineSnapshot(`
+      {
+        "@nrwl/angular:application": {},
+        "@nrwl/angular:host": {},
+        "@nrwl/angular:library": {},
+        "@nrwl/angular:remote": {},
+      }
+    `);
+  });
+
+  it('should only remove karma as default unit test runner from nx.json when set', async () => {
+    // ARRANGE
+    const tree = createTreeWithEmptyWorkspace();
+
+    const nxJson = readNxJson(tree);
+    nxJson.generators = {
+      '@nrwl/angular:application': {
+        style: 'scss',
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:library': {
+        unitTestRunner: 'jest',
+      },
+      '@nrwl/angular:host': {
+        style: 'scss',
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:remote': {
+        unitTestRunner: 'jest',
+      },
+    };
+    updateNxJson(tree, nxJson);
+
+    // ACT
+    await removeKarmaDefaults(tree);
+
+    // ASSERT
+    expect(readNxJson(tree).generators).toMatchInlineSnapshot(`
+      {
+        "@nrwl/angular:application": {
+          "style": "scss",
+        },
+        "@nrwl/angular:host": {
+          "style": "scss",
+        },
+        "@nrwl/angular:library": {
+          "unitTestRunner": "jest",
+        },
+        "@nrwl/angular:remote": {
+          "unitTestRunner": "jest",
+        },
+      }
+    `);
+  });
+
+  it('should not remove karma as default unit test runner from unsupported generator', async () => {
+    // ARRANGE
+    const tree = createTreeWithEmptyWorkspace();
+
+    const nxJson = readNxJson(tree);
+    nxJson.generators = {
+      '@my/custom:plugin': {
+        style: 'scss',
+        unitTestRunner: 'karma',
+      },
+    };
+    updateNxJson(tree, nxJson);
+
+    // ACT
+    await removeKarmaDefaults(tree);
+
+    // ASSERT
+    expect(readNxJson(tree).generators).toMatchInlineSnapshot(`
+      {
+        "@my/custom:plugin": {
+          "style": "scss",
+          "unitTestRunner": "karma",
+        },
+      }
+    `);
+  });
+
+  it('should remove karma as default for project specific generators', async () => {
+    // ARRANGE
+    const tree = createTreeWithEmptyWorkspace();
+    addProjectConfiguration(tree, 'test', {
+      name: 'test',
+      root: '.',
+      sourceRoot: 'src',
+      generators: {
+        '@nrwl/angular:application': {
+          style: 'scss',
+          unitTestRunner: 'karma',
+        },
+      },
+    });
+
+    // ACT
+    await removeKarmaDefaults(tree);
+
+    // ASSERT
+    expect(readProjectConfiguration(tree, 'test').generators)
+      .toMatchInlineSnapshot(`
+      {
+        "@nrwl/angular:application": {
+          "style": "scss",
+        },
+      }
+    `);
+  });
+
+  it('should remove karma when using nested generator default syntax', async () => {
+    // ARRANGE
+    const tree = createTreeWithEmptyWorkspace();
+
+    const nxJson = readNxJson(tree);
+    nxJson.generators = {
+      '@nrwl/angular:application': {
+        style: 'scss',
+        unitTestRunner: 'karma',
+      },
+      '@nrwl/angular:library': {
+        unitTestRunner: 'jest',
+      },
+      '@nrwl/angular': {
+        host: {
+          style: 'scss',
+          unitTestRunner: 'karma',
+        },
+        remote: {
+          unitTestRunner: 'jest',
+        },
+      },
+    };
+    updateNxJson(tree, nxJson);
+
+    // ACT
+    await removeKarmaDefaults(tree);
+
+    // ASSERT
+    expect(readNxJson(tree).generators).toMatchInlineSnapshot(`
+      {
+        "@nrwl/angular": {
+          "host": {
+            "style": "scss",
+          },
+          "remote": {
+            "unitTestRunner": "jest",
+          },
+        },
+        "@nrwl/angular:application": {
+          "style": "scss",
+        },
+        "@nrwl/angular:library": {
+          "unitTestRunner": "jest",
+        },
+      }
+    `);
+  });
+});
diff --git a/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.ts b/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.ts
new file mode 100644
index 0000000000000..c816ddc625fca
--- /dev/null
+++ b/packages/angular/src/migrations/update-16-0-0/remove-karma-defaults.ts
@@ -0,0 +1,83 @@
+import type {
+  NxJsonConfiguration,
+  ProjectConfiguration,
+  Tree,
+} from '@nx/devkit';
+import {
+  formatFiles,
+  getProjects,
+  readNxJson,
+  updateNxJson,
+  updateProjectConfiguration,
+} from '@nx/devkit';
+
+const GENERATORS = ['application', 'library', 'host', 'remote'];
+const CANDIDATE_GENERATOR_COLLECTIONS = ['@nrwl/angular', '@nx/angular'];
+
+export default async function removeKarmaDefaults(tree: Tree) {
+  const nxJson = readNxJson(tree);
+
+  if (nxJson.generators) {
+    const updatedConfig = updateUnitTestRunner(nxJson.generators);
+
+    if (updatedConfig) {
+      updateNxJson(tree, nxJson);
+    }
+  }
+
+  const projects = getProjects(tree);
+
+  for (const [projectName, projectConfig] of projects) {
+    if (projectConfig.generators) {
+      const updatedProject = updateUnitTestRunner(projectConfig.generators);
+
+      if (updatedProject) {
+        updateProjectConfiguration(tree, projectName, projectConfig);
+      }
+    }
+  }
+
+  await formatFiles(tree);
+}
+
+function updateUnitTestRunner(
+  generatorsConfig:
+    | NxJsonConfiguration['generators']
+    | ProjectConfiguration['generators']
+) {
+  const generators = Object.entries(generatorsConfig);
+
+  let updatedConfig = false;
+  for (const [generatorName, generatorDefaults] of generators) {
+    if (CANDIDATE_GENERATOR_COLLECTIONS.includes(generatorName)) {
+      for (const possibleGenerator of GENERATORS) {
+        if (
+          generatorDefaults[possibleGenerator] &&
+          generatorDefaults[possibleGenerator]['unitTestRunner'] &&
+          generatorDefaults[possibleGenerator]['unitTestRunner'] === 'karma'
+        ) {
+          generatorsConfig[generatorName][possibleGenerator]['unitTestRunner'] =
+            undefined;
+          updatedConfig = true;
+        }
+      }
+    }
+
+    if (
+      !GENERATORS.map((v) => `@nrwl/angular:${v}`).includes(generatorName) &&
+      !GENERATORS.map((v) => `@nx/angular:${v}`).includes(generatorName)
+    ) {
+      continue;
+    }
+
+    if (
+      generatorDefaults['unitTestRunner'] &&
+      generatorDefaults['unitTestRunner'] === 'karma'
+    ) {
+      generatorsConfig[generatorName]['unitTestRunner'] = undefined;
+      updatedConfig = true;
+    }
+  }
+
+  return updatedConfig;
+}