Skip to content

Commit

Permalink
fix: add typescript definitions (#35)
Browse files Browse the repository at this point in the history
* feat: add typescript

* try to lint
  • Loading branch information
bahmutov authored Nov 28, 2022
1 parent 5564de3 commit 20f5329
Show file tree
Hide file tree
Showing 9 changed files with 469 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
# https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v4
with:
build: npm run stop-only
build: npm run stop-only && npm run build

- name: Semantic Release 🚀
uses: cycjimmy/semantic-release-action@v3
Expand Down
3 changes: 1 addition & 2 deletions cypress/e2e/children/children-spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="cypress" />
import { really, map, invoke, toDate } from '../../..'
import { really, invoke } from '../../..'

describe(
'count children elements',
Expand Down
89 changes: 89 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
declare function really(): (value: unknown) => any;
declare function pipe(...fns: Function[]): (value: unknown) => unknown;
/**
* Transforms an object or a list of objects using the supplied function or name of the property.
* @param {Function} fn Function to apply to each object
* @returns {Object|Array} Transformed value
* @example cy.get('.todo').then(map('innerText'))
*/
declare function map(fn: Function): (list: unknown) => any;
/**
* Filter the values by the given predicate function.
* @param {Function} predicate
*/
declare function filter(predicate: Function): (list: unknown) => any;
/**
* Invokes the given name (with optional arguments) on the given object.
* @param {String} methodName
* @param {...any} args
* @returns Result of the method invocation
* @example
* cy.get('dates')
* .then(map('innerText'))
* .then(toDate)
* .then(invoke('getTime'))
*/
declare function invoke(methodName: string, ...args: unknown[]): (list: unknown | unknown[]) => any;
/**
* Grabs a property or a nested path from the given object.
* @param {String} path
* @returns Value of the property
* @example
* cy.wrap({ foo: 'bar' }).then(its('foo'))
*/
declare function its(path: string): (o: object) => unknown;
/**
* Curried > N function
* @param {number} n
* @returns Boolean
* @example
* expect(greaterThan(10)(5)).to.be.false
*/
declare function greaterThan(n: number): (x: number) => boolean;
/**
* Curried deep comparison
* @param {any} isEqual
*/
declare function isEqual(expectedValue: any): (actualValue: any) => boolean;
/**
* Takes a function and returns a function that expects the first two
* arguments in the reverse order.
* @param {Function} fn Function to call
* @returns Function
* @example
* flipTwoArguments(Cypress._.map)(x => x * 2, [1, 2, 3])
*/
declare function flipTwoArguments(fn: Function): (a: unknown, b: unknown) => any;
/**
* Converts the given string into a JavaScript Date object
* @param {String} s dateString
* @returns {Date} Date instance
* @deprecated Use "constructor(Date)" instead
*/
declare function toDate(s: string): Date;
/**
* Returns a function that waits for the argument, passes that argument
* to the given callback, but returns the original value. Useful
* for debugging data transformations.
* @param {Function} fn
* @example cyw.wrap(1).then(tap(console.log)).should('equal', 1)
*/
declare function tap(fn: Function): (x: unknown) => unknown;
/**
* Returns a function with the first argument bound.
* @param {Function} fn Function to partially apply
* @param {any} a First argument to apply
* @example
* const add = (a, b) => a + b
* const addOne = partial(add, 1)
* addOne(2) // 3
*/
declare function partial(fn: Function, a: unknown): any;
/**
* Given a constructor function, returns a function
* that waits for a single argument before calling "new constructor(arg)"
* @example constructor(Date)
* @see https://glebbahmutov.com/blog/work-around-the-keyword-new-in-javascript/
*/
declare function construct(constructor: Function): (arg: unknown) => any;
//# sourceMappingURL=index.d.ts.map
1 change: 1 addition & 0 deletions dist/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

208 changes: 208 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
"use strict";
/// <reference types="cypress" />
function really() {
if (!arguments.length) {
throw new Error('really() needs arguments really badly');
}
const fns = Cypress._.takeWhile(arguments, (arg) => typeof arg === 'function');
const chainerIndex = Cypress._.findIndex(arguments, (arg) => typeof arg === 'string');
if (chainerIndex === -1) {
throw new Error('sh: no chainer found');
}
const chainer = arguments[chainerIndex];
const chainerArguments = Cypress._.slice(arguments, chainerIndex + 1);
const chainers = chainer.split('.');
const fn = pipe(...fns);
return function (value) {
// console.log('value', value)
const transformed = fn(value);
// console.log('transformed', transformed)
return chainers.reduce((acc, chainer) => {
const currentChainer = acc[chainer];
if (typeof currentChainer === 'function') {
return acc[chainer](...chainerArguments);
}
else {
return acc[chainer];
}
}, expect(transformed).to);
};
}
function pipe(...fns) {
return function (value) {
return fns.reduce((acc, fn) => fn(acc), value);
};
}
/**
* Transforms an object or a list of objects using the supplied function or name of the property.
* @param {Function} fn Function to apply to each object
* @returns {Object|Array} Transformed value
* @example cy.get('.todo').then(map('innerText'))
*/
function map(fn) {
return function (list) {
if (Cypress._.isArrayLike(list)) {
const callbackFn = typeof fn === 'function' ? (x) => fn(x) : fn;
return Cypress._.map(list, callbackFn);
}
else {
return fn(list);
}
};
}
/**
* Filter the values by the given predicate function.
* @param {Function} predicate
*/
function filter(predicate) {
return function (list) {
if (Cypress._.isArrayLike(list)) {
const callbackFn = typeof predicate === 'function'
? (x) => predicate(x)
: predicate;
return Cypress._.filter(list, callbackFn);
}
else {
return predicate(list);
}
};
}
/**
* Invokes the given name (with optional arguments) on the given object.
* @param {String} methodName
* @param {...any} args
* @returns Result of the method invocation
* @example
* cy.get('dates')
* .then(map('innerText'))
* .then(toDate)
* .then(invoke('getTime'))
*/
function invoke(methodName, ...args) {
return function (list) {
if (arguments.length > 1) {
// the user tried to pass extra arguments with the list/object
// that is a mistake!
throw new Error(`Call to "${methodName}" must have a single argument`);
}
// @ts-ignore
if (typeof list[methodName] === 'function') {
// @ts-ignore
return list[methodName](...args);
}
if (Cypress._.isArrayLike(list)) {
return Cypress._.invokeMap(list, methodName, ...args);
}
else {
return Cypress._.invoke(list, methodName, ...args);
}
};
}
/**
* Grabs a property or a nested path from the given object.
* @param {String} path
* @returns Value of the property
* @example
* cy.wrap({ foo: 'bar' }).then(its('foo'))
*/
function its(path) {
return function (o) {
return Cypress._.property(path)(o);
};
}
/**
* Curried > N function
* @param {number} n
* @returns Boolean
* @example
* expect(greaterThan(10)(5)).to.be.false
*/
function greaterThan(n) {
return function (x) {
return x > n;
};
}
/**
* Curried deep comparison
* @param {any} isEqual
*/
function isEqual(expectedValue) {
return function (actualValue) {
return Cypress._.isEqual(actualValue, expectedValue);
};
}
/**
* Takes a function and returns a function that expects the first two
* arguments in the reverse order.
* @param {Function} fn Function to call
* @returns Function
* @example
* flipTwoArguments(Cypress._.map)(x => x * 2, [1, 2, 3])
*/
function flipTwoArguments(fn) {
return function (a, b) {
return fn(b, a);
};
}
/**
* Converts the given string into a JavaScript Date object
* @param {String} s dateString
* @returns {Date} Date instance
* @deprecated Use "constructor(Date)" instead
*/
function toDate(s) {
return new Date(s);
}
/**
* Returns a function that waits for the argument, passes that argument
* to the given callback, but returns the original value. Useful
* for debugging data transformations.
* @param {Function} fn
* @example cyw.wrap(1).then(tap(console.log)).should('equal', 1)
*/
function tap(fn) {
return function (x) {
fn(x);
return x;
};
}
/**
* Returns a function with the first argument bound.
* @param {Function} fn Function to partially apply
* @param {any} a First argument to apply
* @example
* const add = (a, b) => a + b
* const addOne = partial(add, 1)
* addOne(2) // 3
*/
function partial(fn, a) {
return fn.bind(null, a);
}
/**
* Given a constructor function, returns a function
* that waits for a single argument before calling "new constructor(arg)"
* @example constructor(Date)
* @see https://glebbahmutov.com/blog/work-around-the-keyword-new-in-javascript/
*/
function construct(constructor) {
return function (arg) {
// @ts-ignore
return new constructor(arg);
};
}
module.exports = {
really,
// utility functions
map,
construct,
invoke,
filter,
its,
pipe,
toDate,
tap,
partial,
isEqual,
greaterThan,
flipTwoArguments,
};
22 changes: 21 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
"name": "cypress-should-really",
"version": "0.0.0-development",
"description": "Functional helpers for constructing Cypress should callbacks",
"main": "src",
"main": "dist",
"types": "dist/index.d.ts",
"files": [
"src"
"src",
"dist"
],
"scripts": {
"test": "cypress run",
"semantic-release": "semantic-release",
"stop-only": "stop-only --folder cypress/e2e"
"stop-only": "stop-only --folder cypress/e2e",
"build": "tsc -b",
"watch": "tsc -w",
"lint": "tsc --noEmit"
},
"repository": {
"type": "git",
Expand All @@ -29,6 +34,7 @@
"cypress": "^11.2.0",
"prettier": "2.7.1",
"semantic-release": "19.0.5",
"stop-only": "3.1.2"
"stop-only": "3.1.2",
"typescript": "^4.9.3"
}
}
Loading

0 comments on commit 20f5329

Please sign in to comment.