Repository: mkls/mock-google-cloud-pubsub
Pull request #15: chore: setup prettier and format project
Author: login: toomuchdesign
Created: 2025-04-07T09:49:12Z | Merged: 2025-04-07T16:22:50Z



Diff:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4c19c14..e8951cd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,7 +9,7 @@ env:
   CI: true
   GCP_PROJECT_ID: mock-gcp-project
   PUBSUB_EMULATOR_HOST: localhost:8685
-  GCP_CREDENTIALS: "{}"
+  GCP_CREDENTIALS: '{}'
 
 jobs:
   test-and-build:
@@ -19,18 +19,22 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
+      - name: Run docker compose
+        uses: hoverkraft-tech/compose-action@v2.0.1
+        with:
+          compose-file: './docker-compose.yml'
+
       - uses: actions/setup-node@v4
         with:
           node-version-file: .nvmrc
 
-      - run: npm i
+      - run: npm install
 
-      - name: Run docker compose
-        uses: hoverkraft-tech/compose-action@v2.0.1
-        with:
-          compose-file: "./docker-compose.yml"
+      - name: Check code format
+        run: npm run prettier:check
 
-      - run: npm t
+      - name: Run unit tests
+        run: npm run test
 
       - uses: actions/upload-artifact@v4
         with:
@@ -52,4 +56,4 @@ jobs:
 
       - uses: coverallsapp/github-action@v2
         with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+          github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index f01862a..8181a53 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
 node_modules/
-confidential.env
-coverage
\ No newline at end of file
+coverage
+*.env
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..544138b
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,3 @@
+{
+  "singleQuote": true
+}
diff --git a/README.md b/README.md
index 74aade8..d87e193 100644
--- a/README.md
+++ b/README.md
@@ -75,4 +75,4 @@ Run tests with `npm t` or `npm run test:watch` for watch mode.
 [coveralls-badge]: https://coveralls.io/repos/github/mkls/mock-google-cloud-pubsub/badge.svg?branch=master
 [coveralls]: https://coveralls.io/github/mkls/mock-google-cloud-pubsub?branch=master
 [npm]: https://www.npmjs.com/package/mock-google-cloud-pubsub
-[npm-version-badge]: https://img.shields.io/npm/v/mock-google-cloud-pubsub.svg
\ No newline at end of file
+[npm-version-badge]: https://img.shields.io/npm/v/mock-google-cloud-pubsub.svg
diff --git a/docker-compose.yml b/docker-compose.yml
index 104617f..b3fa815 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,4 @@
-version: "3"
+version: '3'
 
 services:
   pubsub:
diff --git a/jest.config.js b/jest.config.js
index d4d80c6..49a72e4 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -2,5 +2,5 @@ module.exports = {
   testTimeout: 10000,
   collectCoverage: true,
   coverageReporters: ['lcov', 'text'],
-  collectCoverageFrom: ['<rootDir>/src/**/*.{ts,js}']
+  collectCoverageFrom: ['<rootDir>/src/**/*.{ts,js}'],
 };
diff --git a/package.json b/package.json
index 55324ab..cc8f5b5 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,9 @@
   "main": "src/mock-pubsub.js",
   "scripts": {
     "test": "jest .",
-    "test:watch": "npm run test -- --watchAll"
+    "test:watch": "npm run test -- --watchAll",
+    "prettier:check": "prettier . --check",
+    "prettier:fix": "npm run prettier:check -- --write"
   },
   "repository": {
     "type": "git",
@@ -25,6 +27,7 @@
     "@types/jest": "^25.1.3",
     "delay": "^4.3.0",
     "dotenv-haphap": "^3.1.0",
-    "jest": "^29.7.0"
+    "jest": "^29.7.0",
+    "prettier": "^3.5.3"
   }
 }
diff --git a/src/mock-pubsub.js b/src/mock-pubsub.js
index 64fd61f..350ebb8 100644
--- a/src/mock-pubsub.js
+++ b/src/mock-pubsub.js
@@ -57,30 +57,36 @@ const createTopic = (projectId, name) => ({
   async publish(data, attributes) {
     await delay(5);
     const message = { data, attributes };
-    this._subscriptions.forEach(name => {
+    this._subscriptions.forEach((name) => {
       subscriptions[name]._addMessage(message);
     });
   },
   async publishMessage(messageOptions) {
     await delay(5);
-    let message = {}
+    let message = {};
 
-    if (messageOptions.data){
-      message = { data: messageOptions.data, attributes: messageOptions.attributes };
+    if (messageOptions.data) {
+      message = {
+        data: messageOptions.data,
+        attributes: messageOptions.attributes,
+      };
     }
 
-    if (messageOptions.json){
-      message = { data: JSON.stringify(messageOptions.json), attributes: messageOptions.attributes };
+    if (messageOptions.json) {
+      message = {
+        data: JSON.stringify(messageOptions.json),
+        attributes: messageOptions.attributes,
+      };
     }
 
-    this._subscriptions.forEach(name => {
+    this._subscriptions.forEach((name) => {
       subscriptions[name]._addMessage(message);
     });
   },
   setPublishOptions() {},
   subscription(subscriptionName) {
     return getSubscriptionObject(projectId, subscriptionName);
-  }
+  },
 });
 
 const getSubscriptionObject = (projectId, subscriptionName) => {
@@ -93,10 +99,10 @@ const getSubscriptionObject = (projectId, subscriptionName) => {
 const nonExisitingTopic = {
   async delete() {
     throw libError(5, 'NOT_FOUND: Topic not found');
-  }
+  },
 };
 
-const createSubscription = name => ({
+const createSubscription = (name) => ({
   name,
   _listeners: [],
   _undeliveredMessages: [],
@@ -106,7 +112,9 @@ const createSubscription = name => ({
   on(eventName, listener) {
     if (eventName !== 'message') return;
     this._listeners.push(listener);
-    this._undeliveredMessages.forEach(message => pickRandom(this._listeners)(message));
+    this._undeliveredMessages.forEach((message) =>
+      pickRandom(this._listeners)(message),
+    );
     this._undeliveredMessages = [];
   },
   removeAllListeners() {
@@ -120,20 +128,20 @@ const createSubscription = name => ({
       nack: async () => {
         await delay(10);
         this._addMessage(message);
-      }
+      },
     };
     if (this._listeners.length > 0) {
       pickRandom(this._listeners)(messageWithAck);
     } else {
       this._undeliveredMessages.push(messageWithAck);
     }
-  }
+  },
 });
 
 const nonExisitingSubscription = {
   async delete() {
     throw libError(5, 'NOT_FOUND: Subscription does not exist');
-  }
+  },
 };
 
 const libError = (code, message) => {
@@ -142,6 +150,6 @@ const libError = (code, message) => {
   return error;
 };
 
-const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
+const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
 
-const pickRandom = list => list[Math.floor(Math.random() * list.length)];
+const pickRandom = (list) => list[Math.floor(Math.random() * list.length)];
diff --git a/test/mock-pubsub.spec.js b/test/mock-pubsub.spec.js
index c3c4c68..a285fef 100644
--- a/test/mock-pubsub.spec.js
+++ b/test/mock-pubsub.spec.js
@@ -8,23 +8,28 @@ const { PubSub } = require('@google-cloud/pubsub');
 const prefix = process.env.RESOURCE_PREFIX || 'mock-pubsub-prefix-';
 const projectId = process.env.GCP_PROJECT_ID;
 
-const prefixedName = name => `${prefix}${name}`;
+const prefixedName = (name) => `${prefix}${name}`;
 
 [
   {
     title: 'Real PubSub',
-    pubsub: new PubSub({ projectId, credentials: JSON.parse(process.env.GCP_CREDENTIALS) })
+    pubsub: new PubSub({
+      projectId,
+      credentials: JSON.parse(process.env.GCP_CREDENTIALS),
+    }),
   },
-  { title: 'Mock PubSub', pubsub: new MockPubSub({ projectId }) }
+  { title: 'Mock PubSub', pubsub: new MockPubSub({ projectId }) },
 ].forEach(({ title, pubsub }) => {
   describe(title, () => {
     const getPrefixedTopics = async () => {
       const [topics] = await pubsub.getTopics();
-      return topics.filter(topic => topic.name.includes(`topics/${prefix}`));
+      return topics.filter((topic) => topic.name.includes(`topics/${prefix}`));
     };
     const getPrefixedSubscriptions = async () => {
       const [subscriptions] = await pubsub.getSubscriptions();
-      return subscriptions.filter(topic => topic.name.includes(`subscriptions/${prefix}`));
+      return subscriptions.filter((topic) =>
+        topic.name.includes(`subscriptions/${prefix}`),
+      );
     };
 
     beforeEach(async () => {
@@ -43,7 +48,9 @@ const prefixedName = name => `${prefix}${name}`;
 
           const [topic] = await pubsub.createTopic(topicName);
 
-          expect(topic.name).toEqual(`projects/${projectId}/topics/${topicName}`);
+          expect(topic.name).toEqual(
+            `projects/${projectId}/topics/${topicName}`,
+          );
           expect(typeof topic.setPublishOptions).toEqual('function');
         });
 
@@ -55,7 +62,9 @@ const prefixedName = name => `${prefix}${name}`;
             await pubsub.createTopic(topicName);
             throw new Error('should throw before');
           } catch (error) {
-            expect(error.message).toEqual('6 ALREADY_EXISTS: Topic already exists');
+            expect(error.message).toEqual(
+              '6 ALREADY_EXISTS: Topic already exists',
+            );
             expect(error.code).toEqual(6);
           }
         });
@@ -65,15 +74,17 @@ const prefixedName = name => `${prefix}${name}`;
         it('should return exisiting topics', async () => {
           await Promise.all([
             pubsub.createTopic(prefixedName('t1')),
-            pubsub.createTopic(prefixedName('t2'))
+            pubsub.createTopic(prefixedName('t2')),
           ]);
 
           const [topics] = await pubsub.getTopics();
 
-          const topicNames = topics.map(t => t.name).filter(name => name.includes(prefix));
+          const topicNames = topics
+            .map((t) => t.name)
+            .filter((name) => name.includes(prefix));
           expect(topicNames).toEqual([
             `projects/${projectId}/topics/${prefixedName('t1')}`,
-            `projects/${projectId}/topics/${prefixedName('t2')}`
+            `projects/${projectId}/topics/${prefixedName('t2')}`,
           ]);
         });
       });
@@ -82,21 +93,23 @@ const prefixedName = name => `${prefix}${name}`;
         it('should delete a topic', async () => {
           await Promise.all([
             pubsub.createTopic(prefixedName('t1')),
-            pubsub.createTopic(prefixedName('t2'))
+            pubsub.createTopic(prefixedName('t2')),
           ]);
 
           await pubsub.topic(prefixedName('t1')).delete();
 
           const topics = await getPrefixedTopics();
-          expect(topics.map(t => t.name)).toEqual([
-            `projects/${projectId}/topics/${prefixedName('t2')}`
+          expect(topics.map((t) => t.name)).toEqual([
+            `projects/${projectId}/topics/${prefixedName('t2')}`,
           ]);
         });
 
         it('should delete topic by its full name', async () => {
           await pubsub.createTopic(prefixedName('tod'));
 
-          await pubsub.topic(`projects/${projectId}/topics/${prefixedName('tod')}`).delete();
+          await pubsub
+            .topic(`projects/${projectId}/topics/${prefixedName('tod')}`)
+            .delete();
 
           const topics = await getPrefixedTopics();
           expect(topics).toEqual([]);
@@ -116,10 +129,12 @@ const prefixedName = name => `${prefix}${name}`;
       describe('topic.createSubscription', () => {
         it('should create a subscription', async () => {
           const [topic] = await pubsub.createTopic(prefixedName('ted'));
-          const [subscription] = await topic.createSubscription(prefixedName('ted'));
+          const [subscription] = await topic.createSubscription(
+            prefixedName('ted'),
+          );
 
           expect(subscription.name).toEqual(
-            `projects/${projectId}/subscriptions/${prefixedName('ted')}`
+            `projects/${projectId}/subscriptions/${prefixedName('ted')}`,
           );
         });
 
@@ -131,7 +146,9 @@ const prefixedName = name => `${prefix}${name}`;
             await topic.createSubscription(prefixedName('lajos'));
             throw new Error('should throw before');
           } catch (error) {
-            expect(error.message).toEqual('6 ALREADY_EXISTS: Subscription already exists');
+            expect(error.message).toEqual(
+              '6 ALREADY_EXISTS: Subscription already exists',
+            );
             expect(error.code).toEqual(6);
           }
         });
@@ -145,10 +162,12 @@ const prefixedName = name => `${prefix}${name}`;
 
           const [subscriptions] = await pubsub.getSubscriptions();
 
-          const subNames = subscriptions.map(s => s.name).filter(name => name.includes(prefix));
+          const subNames = subscriptions
+            .map((s) => s.name)
+            .filter((name) => name.includes(prefix));
           expect(subNames).toEqual([
             `projects/${projectId}/subscriptions/${prefixedName('l1')}`,
-            `projects/${projectId}/subscriptions/${prefixedName('l2')}`
+            `projects/${projectId}/subscriptions/${prefixedName('l2')}`,
           ]);
         });
       });
@@ -162,8 +181,8 @@ const prefixedName = name => `${prefix}${name}`;
           await pubsub.subscription(prefixedName('l1')).delete();
 
           const subscriptions = await getPrefixedSubscriptions();
-          expect(subscriptions.map(s => s.name)).toEqual([
-            `projects/${projectId}/subscriptions/${prefixedName('l2')}`
+          expect(subscriptions.map((s) => s.name)).toEqual([
+            `projects/${projectId}/subscriptions/${prefixedName('l2')}`,
           ]);
         });
 
@@ -172,7 +191,9 @@ const prefixedName = name => `${prefix}${name}`;
           await topic.createSubscription(prefixedName('l1'));
 
           await pubsub
-            .subscription(`projects/${projectId}/subscriptions/${prefixedName('l1')}`)
+            .subscription(
+              `projects/${projectId}/subscriptions/${prefixedName('l1')}`,
+            )
             .delete();
 
           expect(await getPrefixedSubscriptions()).toEqual([]);
@@ -183,7 +204,9 @@ const prefixedName = name => `${prefix}${name}`;
             await pubsub.subscription(prefixedName('non-let')).delete();
             throw new Error('should throw before');
           } catch (error) {
-            expect(error.message).toEqual('5 NOT_FOUND: Subscription does not exist');
+            expect(error.message).toEqual(
+              '5 NOT_FOUND: Subscription does not exist',
+            );
             expect(error.code).toEqual(5);
           }
         });
@@ -199,7 +222,7 @@ const prefixedName = name => `${prefix}${name}`;
             .subscription(prefixedName('nyul'));
 
           expect(subscription.name).toEqual(
-            `projects/${projectId}/subscriptions/${prefixedName('nyul')}`
+            `projects/${projectId}/subscriptions/${prefixedName('nyul')}`,
           );
         });
       });
@@ -209,13 +232,17 @@ const prefixedName = name => `${prefix}${name}`;
       describe('topic.publish', () => {
         it('should consume messages published to a topic', async () => {
           const [topic] = await pubsub.createTopic(prefixedName('t32'));
-          const [subscription] = await topic.createSubscription(prefixedName('s32'));
-  
+          const [subscription] = await topic.createSubscription(
+            prefixedName('s32'),
+          );
+
           const receivedMessages = [];
-          subscription.on('message', message => receivedMessages.push(message));
-  
+          subscription.on('message', (message) =>
+            receivedMessages.push(message),
+          );
+
           await topic.publish(Buffer.from('Test message!'), { kacsa: 'hap' });
-  
+
           await waitForCondition(() => receivedMessages.length > 0);
           const message = receivedMessages[0];
           expect(message.data.toString()).toEqual('Test message!');
@@ -224,17 +251,24 @@ const prefixedName = name => `${prefix}${name}`;
           expect(typeof message.nack).toEqual('function');
           subscription.removeAllListeners('message');
         });
-      })
+      });
 
       describe('topic.publishMessage({data})', () => {
         it('should consume messages published to a topic', async () => {
           const [topic] = await pubsub.createTopic(prefixedName('t32'));
-          const [subscription] = await topic.createSubscription(prefixedName('s32'));
+          const [subscription] = await topic.createSubscription(
+            prefixedName('s32'),
+          );
 
           const receivedMessages = [];
-          subscription.on('message', message => receivedMessages.push(message));
+          subscription.on('message', (message) =>
+            receivedMessages.push(message),
+          );
 
-          await topic.publishMessage({ data: Buffer.from('Test message!'), attributes: { kacsa: 'hap' }});
+          await topic.publishMessage({
+            data: Buffer.from('Test message!'),
+            attributes: { kacsa: 'hap' },
+          });
 
           await waitForCondition(() => receivedMessages.length > 0);
           const message = receivedMessages[0];
@@ -244,36 +278,47 @@ const prefixedName = name => `${prefix}${name}`;
           expect(typeof message.nack).toEqual('function');
           subscription.removeAllListeners('message');
         });
-      })
+      });
 
       describe('topic.publishMessage({json})', () => {
         it('should consume messages published to a topic', async () => {
           const [topic] = await pubsub.createTopic(prefixedName('t32'));
-          const [subscription] = await topic.createSubscription(prefixedName('s32'));
+          const [subscription] = await topic.createSubscription(
+            prefixedName('s32'),
+          );
 
           const receivedMessages = [];
-          subscription.on('message', message => receivedMessages.push(message));
+          subscription.on('message', (message) =>
+            receivedMessages.push(message),
+          );
 
-          await topic.publishMessage({ json: { data: 'Test message!' }, attributes: { kacsa: 'hap' }});
+          await topic.publishMessage({
+            json: { data: 'Test message!' },
+            attributes: { kacsa: 'hap' },
+          });
 
           await waitForCondition(() => receivedMessages.length > 0);
           const message = receivedMessages[0];
-          expect(JSON.parse(message.data.toString())).toEqual({ data: 'Test message!' });
+          expect(JSON.parse(message.data.toString())).toEqual({
+            data: 'Test message!',
+          });
           expect(message.attributes).toEqual({ kacsa: 'hap' });
           expect(typeof message.ack).toEqual('function');
           expect(typeof message.nack).toEqual('function');
           subscription.removeAllListeners('message');
         });
-      })
+      });
 
       it('should consume messages that were published before subscription consumption was started', async () => {
         const [topic] = await pubsub.createTopic(prefixedName('t34'));
-        const [subscription] = await topic.createSubscription(prefixedName('s34'));
+        const [subscription] = await topic.createSubscription(
+          prefixedName('s34'),
+        );
 
         await topic.publish(Buffer.from('t45'));
 
         const receivedMessages = [];
-        subscription.on('message', message => receivedMessages.push(message));
+        subscription.on('message', (message) => receivedMessages.push(message));
 
         await waitForCondition(() => receivedMessages.length > 0);
         expect(receivedMessages[0].data.toString()).toEqual('t45');
@@ -282,9 +327,11 @@ const prefixedName = name => `${prefix}${name}`;
 
       it('should not receive messages if removeAllListeners was called on subscription', async () => {
         const [topic] = await pubsub.createTopic(prefixedName('t45'));
-        const [subscription] = await topic.createSubscription(prefixedName('s45'));
+        const [subscription] = await topic.createSubscription(
+          prefixedName('s45'),
+        );
         const receivedMessages = [];
-        subscription.on('message', message => receivedMessages.push(message));
+        subscription.on('message', (message) => receivedMessages.push(message));
 
         subscription.removeAllListeners();
 
@@ -295,10 +342,12 @@ const prefixedName = name => `${prefix}${name}`;
 
       it('should only pass messages to "message" event listeners', async () => {
         const [topic] = await pubsub.createTopic(prefixedName('t45'));
-        const [subscription] = await topic.createSubscription(prefixedName('s45'));
+        const [subscription] = await topic.createSubscription(
+          prefixedName('s45'),
+        );
 
         const receivedMessages = [];
-        subscription.on('error', message => receivedMessages.push(message));
+        subscription.on('error', (message) => receivedMessages.push(message));
 
         await topic.publish(Buffer.from('t45'));
         await wait(100);
@@ -307,11 +356,13 @@ const prefixedName = name => `${prefix}${name}`;
 
       it('should redeliver a message if it was nacked', async () => {
         const [topic] = await pubsub.createTopic(prefixedName('t45'));
-        const [subscription] = await topic.createSubscription(prefixedName('s45'));
+        const [subscription] = await topic.createSubscription(
+          prefixedName('s45'),
+        );
 
         const receivedMessages = [];
         let nackedOnce = false;
-        subscription.on('message', message => {
+        subscription.on('message', (message) => {
           receivedMessages.push(message);
           if (!nackedOnce) {
             nackedOnce = true;
@@ -328,12 +379,18 @@ const prefixedName = name => `${prefix}${name}`;
 
       it('should call all listeners randomly when more are attached to a single subscription', async () => {
         const [topic] = await pubsub.createTopic(prefixedName('t34'));
-        const [subscription] = await topic.createSubscription(prefixedName('s34'));
+        const [subscription] = await topic.createSubscription(
+          prefixedName('s34'),
+        );
 
         const receivedMessages1 = [];
-        subscription.on('message', message => receivedMessages1.push(message));
+        subscription.on('message', (message) =>
+          receivedMessages1.push(message),
+        );
         const receivedMessages2 = [];
-        subscription.on('message', message => receivedMessages2.push(message));
+        subscription.on('message', (message) =>
+          receivedMessages2.push(message),
+        );
 
         for (let i = 0; i < 10; i++) {
           await topic.publish(Buffer.from('tm435'));
@@ -347,7 +404,7 @@ const prefixedName = name => `${prefix}${name}`;
   });
 });
 
-const waitForCondition = async isConditionMet => {
+const waitForCondition = async (isConditionMet) => {
   const maxTimeoutMs = 5000;
   const maxWaitCount = 500;
   let waitCount = 0;
@@ -360,8 +417,10 @@ const waitForCondition = async isConditionMet => {
     }
   }
   if (waitCount > maxWaitCount) {
-    throw new Error(`Timed out waiting ${maxTimeoutMs}ms for condition ${isConditionMet}`);
+    throw new Error(
+      `Timed out waiting ${maxTimeoutMs}ms for condition ${isConditionMet}`,
+    );
   }
 };
 
-const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));


Reviews:
user: login: toomuchdesign
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T09:50:00Z
user: login: mkls
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-07T15:02:22Z
user: login: toomuchdesign
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:37:32Z
user: login: toomuchdesign
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:45:14Z
user: login: toomuchdesign
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:50:22Z
user: login: mkls
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-07T15:57:06Z
user: login: mkls
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-07T15:58:26Z
user: login: toomuchdesign
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:01:09Z
user: login: mkls
state: APPROVED
author_association: OWNER
submitted_at: 2025-04-07T16:01:23Z

Review comments:
diff_hunk: @@ -19,15 +19,13 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - uses: actions/setup-node@v4
-        with:
-          node-version-file: .nvmrc
-
-      - run: npm i
-
       - name: Run docker compose
         uses: hoverkraft-tech/compose-action@v2.0.1
         with:
           compose-file: "./docker-compose.yml"
 
-      - run: npm t
+      - uses: actions/setup-node@v4
+        with:
+          node-version-file: .nvmrc
+
+      - run: npm i
path: .github/workflows/ci.yml
user: login: toomuchdesign
body: This will trigger both tests and prettier check by executing `npm run prepare`.
created_at: 2025-04-07T09:50:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,15 +19,13 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - uses: actions/setup-node@v4
-        with:
-          node-version-file: .nvmrc
-
-      - run: npm i
-
       - name: Run docker compose
         uses: hoverkraft-tech/compose-action@v2.0.1
         with:
           compose-file: "./docker-compose.yml"
 
-      - run: npm t
+      - uses: actions/setup-node@v4
+        with:
+          node-version-file: .nvmrc
+
+      - run: npm i
path: .github/workflows/ci.yml
user: login: mkls
body: Using the `prepare` script feels like a bit of hidden magic for me. I think when someone looks at this workflow later, they would understand it easier if there was an explicit call to the test commands that we are running.
Also, I guess it would also run the tests after an `npm i` in local, which might be surprising.
created_at: 2025-04-07T15:01:11Z
author_association: OWNER
diff_hunk: @@ -5,7 +5,11 @@
   "main": "src/mock-pubsub.js",
   "scripts": {
     "test": "jest --testTimeout 60000 --colors",
-    "test:watch": "npm run test -- --watchAll"
+    "test:watch": "npm run test -- --watchAll",
+    "prepare": "npm run source:check && npm run test",
+    "prettier:check": "prettier . --check",
+    "prettier:fix": "npm run prettier:check -- --write",
+    "source:check": "npm run prettier:check"
path: package.json
user: login: mkls
body: do we need this alias? I think we could just use `prettier:check` directly, then we would have one less script, which might make it easier to scan through the available commands.
created_at: 2025-04-07T15:02:18Z
author_association: OWNER
diff_hunk: @@ -5,7 +5,11 @@
   "main": "src/mock-pubsub.js",
   "scripts": {
     "test": "jest --testTimeout 60000 --colors",
-    "test:watch": "npm run test -- --watchAll"
+    "test:watch": "npm run test -- --watchAll",
+    "prepare": "npm run source:check && npm run test",
+    "prettier:check": "prettier . --check",
+    "prettier:fix": "npm run prettier:check -- --write",
+    "source:check": "npm run prettier:check"
path: package.json
user: login: toomuchdesign
body: Happy to remove it. I'm used to add it since it usually run linters and type check. As far as we don't type check, it's useless.
created_at: 2025-04-07T15:37:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,15 +19,13 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - uses: actions/setup-node@v4
-        with:
-          node-version-file: .nvmrc
-
-      - run: npm i
-
       - name: Run docker compose
         uses: hoverkraft-tech/compose-action@v2.0.1
         with:
           compose-file: "./docker-compose.yml"
 
-      - run: npm t
+      - uses: actions/setup-node@v4
+        with:
+          node-version-file: .nvmrc
+
+      - run: npm i
path: .github/workflows/ci.yml
user: login: toomuchdesign
body: Split test and code format task execution 👍 
created_at: 2025-04-07T15:45:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,15 +19,13 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - uses: actions/setup-node@v4
-        with:
-          node-version-file: .nvmrc
-
-      - run: npm i
-
       - name: Run docker compose
         uses: hoverkraft-tech/compose-action@v2.0.1
         with:
           compose-file: "./docker-compose.yml"
 
-      - run: npm t
+      - uses: actions/setup-node@v4
+        with:
+          node-version-file: .nvmrc
+
+      - run: npm i
path: .github/workflows/ci.yml
user: login: toomuchdesign
body: Lockfile vs no lockfile: if no lockfile can help early catching consuming libraries unexpected breaking changes, a lock file guarantees a consistent dev environment for maintainers + a faster `npm install` routine (with [npm ci](https://docs.npmjs.com/cli/v9/commands/npm-ci))
created_at: 2025-04-07T15:50:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,15 +19,13 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - uses: actions/setup-node@v4
-        with:
-          node-version-file: .nvmrc
-
-      - run: npm i
-
       - name: Run docker compose
         uses: hoverkraft-tech/compose-action@v2.0.1
         with:
           compose-file: "./docker-compose.yml"
 
-      - run: npm t
+      - uses: actions/setup-node@v4
+        with:
+          node-version-file: .nvmrc
+
+      - run: npm i
path: .github/workflows/ci.yml
user: login: mkls
body: If you think it is worth it, then I'm fine with adding a lock file.
created_at: 2025-04-07T15:57:06Z
author_association: OWNER
diff_hunk: @@ -5,7 +5,10 @@
   "main": "src/mock-pubsub.js",
   "scripts": {
     "test": "jest .",
-    "test:watch": "npm run test -- --watchAll"
+    "test:watch": "npm run test -- --watchAll",
+    "prepare": "npm run prettier:check && npm run test",
path: package.json
user: login: mkls
body: do we still need this prepare script? It looks like it will run the tests twice in ci now
created_at: 2025-04-07T15:57:46Z
author_association: OWNER
diff_hunk: @@ -5,7 +5,10 @@
   "main": "src/mock-pubsub.js",
   "scripts": {
     "test": "jest .",
-    "test:watch": "npm run test -- --watchAll"
+    "test:watch": "npm run test -- --watchAll",
+    "prepare": "npm run prettier:check && npm run test",
path: package.json
user: login: toomuchdesign
body: Good point. Removed :)
created_at: 2025-04-07T16:01:08Z
author_association: CONTRIBUTOR

PR comments:
user: login: toomuchdesign
created_at: 2025-04-07T15:50:52Z
body: PR ready for another review 👍 
author_association: CONTRIBUTOR
user: login: coveralls
created_at: 2025-04-07T20:13:41Z
body: ## Pull Request Test Coverage Report for [Build 14313993981](https://coveralls.io/builds/73106965)

### Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

- For more information on this, see <a target="_blank" href="https://docs.coveralls.io/build-types#tracking-coverage-changes-with-pull_request-builds">Tracking coverage changes with pull request builds</a>.
- To avoid this issue with future PRs, see these <a target="_blank" href="https://docs.coveralls.io/build-types#recommended-ci-configurations">Recommended CI Configurations</a>.
- For a quick fix, <a target="_blank" href="https://github.blog/changelog/2022-02-03-more-ways-to-keep-your-pull-request-branch-up-to-date/#update-your-pull-request-branch-by-rebasing">rebase this PR at GitHub</a>. Your next report should be accurate.

### Details

* **12** of **12**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.03%**) to **97.674%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/73106965/badge)](https://coveralls.io/builds/73106965) |
| :-- | --: |
| Change from base [Build 14313879178](https://coveralls.io/builds/73106849): |  0.03% |
| Covered Lines: | 64 |
| Relevant Lines: | 64 |

---
##### 💛  - [Coveralls](https://coveralls.io)

author_association: NONE