Repository: bahmutov/cypress-map
Pull request #17 (2023-02-03 13:15:54)

feat: add cy.partial query


Patch:
diff --git a/README.md b/README.md
index 3cdbb7f..fad9420 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,21 @@ const double = (n) => n * 2
 cy.wrap(100).apply(double).should('equal', 200)
 ```
 
+### partial
+
+Sometimes you have the callback to apply, and you know the first argument(s), and just need to put the subject at the last position. This is where you can partially apply the known arguments to the given callback.
+
+```js
+// the Cypress._.add takes to arguments (a, b)
+// we know the first argument a = 5
+// so we partially apply it and wait for the subject = b argument
+cy.wrap(100).partial(Cypress._.add, 5).should('equal', 105)
+// same as
+cy.wrap(100)
+  .apply((subject) => Cypress._.add(5, subject))
+  .should('equal', 105)
+```
+
 ### map
 
 ```js
diff --git a/commands/index.d.ts b/commands/index.d.ts
index 4d04109..c465666 100644
--- a/commands/index.d.ts
+++ b/commands/index.d.ts
@@ -59,6 +59,16 @@ declare namespace Cypress {
      */
     apply(fn: Function): Chainable<any>
 
+    /**
+     * Creates a callback to apply to the subject by partially applying known arguments.
+     * @see https://github.com/bahmutov/cypress-map
+     * @param fn Callback function to call
+     * @param knownArguments The first argument(s) to the callback
+     * @example
+     *  cy.wrap(2).partial(Cypress._.add, 4).should('equal', 6)
+     */
+    partial(fn: Function, ...knownArguments: unknown[]): Chainable<any>
+
     /**
      * A query command that returns the first element / item from the subject.
      * @see https://github.com/bahmutov/cypress-map
diff --git a/commands/index.js b/commands/index.js
index 80c97f0..9e90d83 100644
--- a/commands/index.js
+++ b/commands/index.js
@@ -13,3 +13,4 @@ import './print'
 import './table'
 import './invoke-once'
 import './update'
+import './partial'
diff --git a/commands/partial.js b/commands/partial.js
new file mode 100644
index 0000000..d8fb648
--- /dev/null
+++ b/commands/partial.js
@@ -0,0 +1,21 @@
+/// <reference types="cypress" />
+
+Cypress.Commands.addQuery('partial', (callback, ...knownArguments) => {
+  if (typeof callback !== 'function') {
+    throw new Error('Expected a function to partially apply')
+  }
+
+  const applied = callback.bind(null, ...knownArguments)
+  const log = Cypress.log({
+    name: 'partial',
+    message: `${callback.name} with ${knownArguments.join(',')}`,
+  })
+
+  return (subject) => {
+    log.set({
+      $el: subject,
+    })
+
+    return applied(subject)
+  }
+})
diff --git a/commands/update.js b/commands/update.js
index 4131827..a7e279b 100644
--- a/commands/update.js
+++ b/commands/update.js
@@ -7,7 +7,7 @@ Cypress.Commands.addQuery('update', (prop, callback) => {
 
   const log = Cypress.log({
     name: 'update',
-    message: `${prop} with ${callback.name}`,
+    message: `${prop} by ${callback.name}`,
   })
 
   return (subject) => {


Test patch:
diff --git a/cypress/e2e/partial.cy.js b/cypress/e2e/partial.cy.js
new file mode 100644
index 0000000..10727c8
--- /dev/null
+++ b/cypress/e2e/partial.cy.js
@@ -0,0 +1,8 @@
+/// <reference types="cypress" />
+// @ts-check
+
+import '../../commands'
+
+it('applies the partially applied callback', () => {
+  cy.wrap(100).partial(Cypress._.add, 5).should('equal', 105)
+})
diff --git a/cypress/e2e/table-rows.cy.js b/cypress/e2e/table-rows.cy.js
index f7aef8e..c9c6eff 100644
--- a/cypress/e2e/table-rows.cy.js
+++ b/cypress/e2e/table-rows.cy.js
@@ -81,4 +81,22 @@ describe('table rows', { viewportWidth: 300, viewportHeight: 200 }, () => {
         }),
       )
   })
+
+  it('confirms the first row with partial, update, and cy-spok', () => {
+    cy.get('table tbody tr')
+      .first()
+      .find('td')
+      .map('innerText')
+      .print()
+      .partial(Cypress._.zipObject, headings)
+      .update('Age', Number)
+      .print()
+      .should(
+        spok({
+          Name: 'Dave',
+          Age: spok.range(1, 99),
+          'Date (YYYY-MM-DD)': spok.test(/^\d\d\d\d-\d\d-\d\d$/),
+        }),
+      )
+  })
 })