Compare commits

..

No commits in common. "c600385fab6d90cc1458b88e0ccdb7270e96b4ea" and "8a726b386ed0d995de81ca7816f3b005a4a229bd" have entirely different histories.

19 changed files with 1378 additions and 2656 deletions

75
.drone.yml Normal file
View file

@ -0,0 +1,75 @@
---
kind: pipeline
name: deployment
steps:
- name: build
image: node
commands:
- yarn install --frozen-lockfile
- yarn build
- name: test
image: node
commands:
- yarn test
depends_on:
- build
- name: lint
image: node
commands:
- yarn lint
depends_on:
- build
- name: deploy
image: plugins/npm
settings:
username: vylpes
password:
from_secret: npm_password
email: ethan@vylpes.com
token:
from_secret: npm_token
depends_on:
- test
- lint
trigger:
branch:
- master
event:
- push
- tag
---
kind: pipeline
name: integration
steps:
- name: build
image: node
commands:
- yarn install --frozen-lockfile
- yarn build
- name: test
image: node
commands:
- yarn test
depends_on:
- build
- name: lint
image: node
commands:
- yarn lint
depends_on:
- build
trigger:
branch:
- develop
- feature/*
- hotfix/*
- renovate/*
event:
- push

2
.gitignore vendored
View file

@ -1,6 +1,4 @@
node_modules/ node_modules/
dist/ dist/
bin/
coverage/ coverage/
yarn-error.log yarn-error.log
.DS_Store

View file

@ -1,5 +1,5 @@
src/ app.ts
bin/
tests/ tests/
jest.config.cjs jest.config.cjs
jest.setup.js jest.setup.js

View file

@ -1,92 +0,0 @@
steps:
build:
# Build and test
image: node
commands:
- yarn install --frozen-lockfile
- yarn build
when:
event: [ push, pull_request ]
branch: [ hotfix/*, feature/*, renovate/*, develop, main ]
lint:
image: node
commands:
- yarn lint
when:
event: [ push, pull_request ]
branch: [ hotfix/*, feature/*, renovate/*, develop, main ]
test:
image: node
commands:
- yarn test
when:
event: [ push, pull_request ]
branch: [ hotfix/*, feature/*, renovate/*, develop, main ]
# Package production build
package_prod:
image: node
commands:
- apt install unzip -y
- wget https://github.com/xerub/ldid/releases/download/42/ldid.zip
- unzip ldid.zip
- mkdir /opt/ldid/
- cp linux64/ldid /opt/ldid/
- export PATH=/opt/ldid:$PATH
- yarn package
when:
event: tag
branch: main
rsync_prod:
image: alpine
secrets: [ ssh_key ]
commands:
- apk add rsync openssh-client
- eval `ssh-agent -s`
- echo "$SSH_KEY" | tr -d '\r' | ssh-add -
- rsync -e "ssh -o StrictHostKeyChecking=no" -r ./bin vylpes@192.168.1.115:/home/vylpes/apps/random-bunny/random-bunny_prod
when:
event: tag
branch: main
# Package stage build
package_stage:
image: node
commands:
- apt install unzip -y
- wget https://github.com/xerub/ldid/releases/download/42/ldid.zip
- unzip ldid.zip
- mkdir /opt/ldid/
- cp linux64/ldid /opt/ldid/
- export PATH=/opt/ldid:$PATH
- yarn package
when:
event: push
branch: develop
rsync_stage:
image: alpine
secrets: [ ssh_key ]
commands:
- apk add rsync openssh-client
- eval `ssh-agent -s`
- echo "$SSH_KEY" | tr -d '\r' | ssh-add -
- rsync -e "ssh -o StrictHostKeyChecking=no" -r ./bin vylpes@192.168.1.115:/home/vylpes/apps/random-bunny/random-bunny_stage
when:
event: push
branch: develop
# Publish to NPM
publish:
image: plugins/npm
settings:
username:
from_secret: NPM_USERNAME
email:
from_secret: NPM_EMAIL
password:
from_secret: NPM_PASSWORD
api_key:
from_secret: NPM_TOKEN
when:
event: tag
branch: main

9
app.ts Normal file
View file

@ -0,0 +1,9 @@
import randomBunny from "./dist/index.js";
async function app() {
const result = await randomBunny('rabbits', 'hot');
console.log(result);
}
app();

View file

@ -1,97 +0,0 @@
# CLI
Since Version 2.2, Random Bunny contains a command line interface (CLI).
## Downloads
The project can be downloaded as a binary for your system via the [GitHub Releases](https://github.com/Vylpes/random-bunny/releases) or [Gitea Releases](https://gitea.vylpes.xyz/RabbitLabs/random-bunny/releases) page.
We currently support:
- Linux (x64)
- Windows (x64)
- macOS (x64, Arm64\*)
The git repository can also be cloned and ran via `yarn build` and `yarn start`.
> **NOTE:** We are aware of a bug in the macOS Arm64 builds failing to execute. For now you're still able to use the x64 builds under Rosetta fine. This will hopefully be fixed in a future release.
## Default Output
By default, the command will fetch a random image from `r/rabbits` and return it in a human-readable output.
```
$ randombunny
Archived = false
Downvotes = 0
Hidden = false
Permalink = /r/Rabbits/comments/1av1rg9/cute_baby_bun/
Subreddit = Rabbits
Subreddit Subscribers = 486084
Title = Cute baby bun
Upvotes = 211
Url = https://i.redd.it/sfz0srdrimjc1.png
```
## Help
The command also includes a help option in case you are stuck.
```
$ randombunny --help
# or
$ randombunny -h
Usage: random-bunny [options]
Get a random image url from a subreddit of your choosing
Options:
-V, --version output the version number
-s, --subreddit <subreddit> The subreddit to search (default: "rabbits")
-j, --json Output as JSON
-q, --query-metadata Include query metadata in result
--sort <sort> Sort by (choices: "hot", "new", "top", default: "hot")
-h, --help display help for command
✨ Done in 0.32s.
```
## JSON output
You can also convert the output into JSON, if you need to input it to another program.
```bash
$ randombunny --json
# or
$ randonbunny -j
{"Archived":false,"Downs":0,"Hidden":false,"Permalink":"/r/Rabbits/comments/1av1rg9/cute_baby_bun/","Subreddit":"Rabbits","SubredditSubscribers":486085,"Title":"Cute baby bun","Ups":210,"Url":"https://i.redd.it/sfz0srdrimjc1.png"}
```
## Sort
You can also choose the sorting option which reddit will use to return the available posts to randomise from.
This defaults to "hot". The valid options are "hot", "new", and "top".
```
$ randombunny --sort hot
$ randombunny --sort new
$ randomBunny --sort top
```
## Subreddit
You can change the subreddit which the command fetches from.
This defaults to "rabbits"
```
$ randombunny --subreddit rabbits
$ randombunny -s horses
```

View file

@ -1,13 +1,11 @@
{ {
"name": "random-bunny", "name": "random-bunny",
"version": "2.2.0", "version": "2.1.6",
"description": "Get a random subreddit image url", "description": "Get a random subreddit image url",
"license": "MIT", "license": "MIT",
"author": "Vylpes", "author": "Vylpes",
"exports": "./dist/index.js", "exports": "./dist/index.js",
"typings": "./dist/index.d.ts", "typings": "./dist/index.d.ts",
"bin": "./dist/cli.js",
"main": "./dist/index.js",
"keywords": [ "keywords": [
"rabbit", "rabbit",
"bunny", "bunny",
@ -18,7 +16,6 @@
"placeholder" "placeholder"
], ],
"dependencies": { "dependencies": {
"commander": "^12.0.0",
"glob-parent": "^6.0.0", "glob-parent": "^6.0.0",
"got-cjs": "^12.5.4", "got-cjs": "^12.5.4",
"htmlparser2": "^9.1.0", "htmlparser2": "^9.1.0",
@ -26,11 +23,10 @@
}, },
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"start": "node dist/cli.js", "start": "ts-node app.ts",
"test": "jest", "test": "jest",
"lint": "eslint .", "lint": "eslint .",
"release": "np --no-publish", "release": "np --no-publish"
"package": "pkg . --no-bytecode"
}, },
"bugs": { "bugs": {
"url": "https://gitea.vylpes.xyz/RabbitLabs/random-bunny/issues", "url": "https://gitea.vylpes.xyz/RabbitLabs/random-bunny/issues",
@ -41,34 +37,24 @@
"devDependencies": { "devDependencies": {
"@types/eslint": "^8.21.1", "@types/eslint": "^8.21.1",
"@types/jest": "^29.5.8", "@types/jest": "^29.5.8",
"@types/node": "^20.0.0", "@types/node": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0", "@typescript-eslint/parser": "^5.54.0",
"eslint": "^8.49.0", "eslint": "^8.49.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-mock-extended": "^3.0.3", "jest-mock-extended": "^3.0.3",
"np": "^9.0.0", "np": "^7.7.0",
"pkg": "^5.8.1",
"ts-jest": "^29.1.1", "ts-jest": "^29.1.1",
"ts-mockito": "^2.6.1", "ts-mockito": "^2.6.1",
"ts-node": "^10.9.1",
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"resolutions": { "resolutions": {
"np/**/got": "^14.0.0", "np/**/got": "^11.8.5",
"**/semver": "^7.5.2", "**/semver": "^7.5.2",
"@babel/traverse": "^7.23.2" "@babel/traverse": "^7.23.2"
}, },
"files": [ "files": [
"dist" "dist"
], ]
"pkg": {
"scripts": "dist/**/*.js",
"targets": [
"latest-linux-x64",
"latest-macos-x64",
"latest-macos-arm64",
"latest-win-x64"
],
"outputPath": "bin"
}
} }

View file

@ -14,10 +14,6 @@ or if you're using yarn
yarn add random-bunny yarn add random-bunny
``` ```
### Binary
The project can be downloaded as a binary for your system via the [GitHub Releases](https://github.com/Vylpes/random-bunny/releases) or [Gitea Releases](https://gitea.vylpes.xyz/RabbitLabs/random-bunny/releases) page.
## Usage ## Usage
@ -48,12 +44,6 @@ The json string which gets returned consists of:
`sortBy` will default to 'hot' if not given or invalid `sortBy` will default to 'hot' if not given or invalid
## CLI
Random bunny can also be used as a CLI. This is accessible via the executable (see git releases) or via `src/cli.ts`
For more details, see the [documentation](https://docs.vylpes.xyz/books/random-bunny).
## Notes ## Notes
* Node 4 or newer. * Node 4 or newer.

View file

@ -1,56 +0,0 @@
import { Command, Option } from "commander";
import randomBunny from "./index";
import ICliOptions from "./contracts/ICliOptions";
import { exit } from "process";
const program = new Command();
program
.name('random-bunny')
.description('Get a random image url from a subreddit of your choosing')
.version('2.2')
.option('-s, --subreddit <subreddit>', 'The subreddit to search', 'rabbits')
.option('-j, --json', 'Output as JSON')
.option('-q, --query-metadata', 'Include query metadata in result')
.addOption(new Option('--sort <sort>', 'Sort by').default('hot').choices(['hot', 'new', 'top']));
program.parse();
const options: ICliOptions = program.opts();
randomBunny(options.subreddit, options.sort)
.then((response) => {
if (response.IsSuccess) {
const result = response.Result!;
const outputLines: string[] = [];
if (options.json) {
console.log(JSON.stringify(result));
return;
}
outputLines.push(`Archived = ${result.Archived}`);
outputLines.push(`Downvotes = ${result.Downs}`);
outputLines.push(`Hidden = ${result.Hidden}`);
outputLines.push(`Permalink = ${result.Permalink}`);
outputLines.push(`Subreddit = ${result.Subreddit}`);
outputLines.push(`Subreddit Subscribers = ${result.SubredditSubscribers}`);
outputLines.push(`Title = ${result.Title}`);
outputLines.push(`Upvotes = ${result.Ups}`);
outputLines.push(`Url = ${result.Url}`);
if (options.queryMetadata != null) {
outputLines.push(`Query.Subreddit = ${response.Query.subreddit}`);
outputLines.push(`Query.Sort By = ${response.Query.sortBy}`);
}
console.log(outputLines.join("\n"));
exit(0);
} else {
const error = response.Error!;
console.error(error.Message, error.Code);
exit(1);
}
});

View file

@ -1,6 +0,0 @@
export enum ErrorCode {
Unknown,
FailedToFetchReddit,
UnableToParseJSON,
NoImageResultsFound,
}

View file

@ -1,5 +0,0 @@
export default class ErrorMessages {
public static readonly FailedToFetchReddit = "Failed to fetch result from Reddit";
public static readonly UnableToParseJSON = "Unable to parse the JSON result";
public static readonly NoImageResultsFound = "No image results found in response from Reddit";
}

View file

@ -1,6 +0,0 @@
export default interface ICliOptions {
subreddit: string,
json?: boolean,
sort: string,
queryMetadata?: boolean,
}

View file

@ -1,6 +0,0 @@
import { ErrorCode } from "../constants/ErrorCode";
export default interface IError {
Code: ErrorCode;
Message: string;
}

View file

@ -1,10 +1,6 @@
import IError from "./IError.js";
import IRedditResult from "./IRedditResult.js"; import IRedditResult from "./IRedditResult.js";
import QueryResult from "./QueryResult.js";
export default interface IReturnResult { export default interface IReturnResult {
IsSuccess: boolean; IsSuccess: boolean;
Query: QueryResult;
Result?: IRedditResult; Result?: IRedditResult;
Error?: IError;
} }

View file

@ -1,4 +0,0 @@
export default interface QueryResult {
subreddit: string,
sortBy: string,
}

View file

@ -1,10 +1,8 @@
import IReturnResult from "./contracts/IReturnResult"; import IReturnResult from "./contracts/IReturnResult.js";
import IRedditResult from "./contracts/IRedditResult"; import IRedditResult from "./contracts/IRedditResult.js";
import fetch from "got-cjs"; import fetch from "got-cjs";
import { List } from 'linqts'; import { List } from 'linqts';
import IFetchResult from "./contracts/IFetchResult"; import IFetchResult from "./contracts/IFetchResult.js";
import { ErrorCode } from "./constants/ErrorCode";
import ErrorMessages from "./constants/ErrorMessages";
import ImageHelper from "./imageHelper"; import ImageHelper from "./imageHelper";
const sortable = [ const sortable = [
@ -13,28 +11,14 @@ const sortable = [
'top' 'top'
]; ];
export default async function randomBunny(subreddit: string, sortBy: string = 'hot'): Promise<IReturnResult> { export default async function randomBunny(subreddit: string, sortBy?: string): Promise<IReturnResult> {
if (!sortable.includes(sortBy)) sortBy = 'hot'; if (!sortBy || !sortable.includes(sortBy)) sortBy = 'hot';
const result = await fetch(`https://reddit.com/r/${subreddit}/${sortBy}.json?limit=100`) const result = await fetch(`https://reddit.com/r/${subreddit}/${sortBy}.json?limit=100`);
.then((res) => {
return res;
})
.catch(() => {
return null;
});
if (!result) { if (!result) {
return { return {
IsSuccess: false, IsSuccess: false
Query: {
subreddit: subreddit,
sortBy: sortBy,
},
Error: {
Code: ErrorCode.FailedToFetchReddit,
Message: ErrorMessages.FailedToFetchReddit,
},
} }
} }
@ -42,15 +26,7 @@ export default async function randomBunny(subreddit: string, sortBy: string = 'h
if (!json) { if (!json) {
return { return {
IsSuccess: false, IsSuccess: false
Query: {
subreddit: subreddit,
sortBy: sortBy,
},
Error: {
Code: ErrorCode.UnableToParseJSON,
Message: ErrorMessages.UnableToParseJSON,
},
} }
} }
@ -65,14 +41,6 @@ export default async function randomBunny(subreddit: string, sortBy: string = 'h
if (dataWithImages.length == 0) { if (dataWithImages.length == 0) {
return { return {
IsSuccess: false, IsSuccess: false,
Query: {
subreddit: subreddit,
sortBy: sortBy,
},
Error: {
Code: ErrorCode.NoImageResultsFound,
Message: ErrorMessages.NoImageResultsFound,
},
}; };
} else { } else {
random = Math.floor((Math.random() * (dataWithImages.length - 1)) + 0); // Between 0 and (size - 1) random = Math.floor((Math.random() * (dataWithImages.length - 1)) + 0); // Between 0 and (size - 1)
@ -90,14 +58,6 @@ export default async function randomBunny(subreddit: string, sortBy: string = 'h
if (!galleryImage) { if (!galleryImage) {
return { return {
IsSuccess: false, IsSuccess: false,
Query: {
subreddit: subreddit,
sortBy: sortBy,
},
Error: {
Code: ErrorCode.NoImageResultsFound,
Message: ErrorMessages.NoImageResultsFound,
},
} }
} }
@ -120,10 +80,6 @@ export default async function randomBunny(subreddit: string, sortBy: string = 'h
return { return {
IsSuccess: true, IsSuccess: true,
Query: {
subreddit: subreddit,
sortBy: sortBy,
},
Result: redditResult Result: redditResult
}; };
} }

View file

@ -1,187 +0,0 @@
import { exec } from "child_process";
import path from "path";
describe('default', () => {
test('GIVEN no options are supplied, EXPECT standard output', async () => {
const result = await cli([], '.');
const keys = result.stdout.split('\n')
.flatMap(x => x.split(' = ')[0])
.filter(x => x && x.length > 0);
const values = result.stdout.split('\n')
.flatMap(x => x.split(' = ')[1])
.filter(x => x && x.length > 0);
expect(result.code).toBe(0);
expect(keys).toStrictEqual(['Archived', 'Downvotes', 'Hidden', 'Permalink', 'Subreddit', 'Subreddit Subscribers', 'Title', 'Upvotes', 'Url']);
expect(values.length).toBe(9);
}, 5000);
test('GIVEN an error occurs, EXPECT error output', async () => {
const result = await cli(['-s', 'textonly'], '.');
expect(result.code).toBe(1);
expect(result.stderr).toBeDefined();
}, 5000);
});
describe('version', () => {
test('GIVEN -V flag is supplied, EXPECT version returned', async () => {
const result = await cli(['-V'], '.');
expect(result.code).toBe(0);
expect(result.stdout).toBe('2.2\n');
});
test('GIVEN --version is supplied, EXPECT version returned', async () => {
const result = await cli(['--version'], '.');
expect(result.code).toBe(0);
expect(result.stdout).toBe('2.2\n');
});
});
describe('help', () => {
test('GIVEN -h is supplied, EXPECT help returned', async () => {
const result = await cli(['-h'], '.');
expect(result.code).toBe(0);
expect(result.stdout.split('\n')[0]).toBe('Usage: random-bunny [options]');
});
test('GIVEN --help is supplied, EXPECT help returned', async () => {
const result = await cli(['--help'], '.');
expect(result.code).toBe(0);
expect(result.stdout.split('\n')[0]).toBe('Usage: random-bunny [options]');
});
});
describe('subreddit', () => {
test('GIVEN -s is not supplied, EXPECT subreddit to be defaulted', async () => {
const result = await cli([], '.');
const subreddit = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0] == 'Subreddit')!
.split(' = ')[1];
expect(subreddit).toBe('Rabbits');
}, 5000);
test('GIVEN -s is supplied, EXPECT subreddit to be changed', async () => {
const result = await cli(['-s', 'pics'], '.');
const subreddit = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0] == 'Subreddit')!
.split(' = ')[1];
expect(subreddit).toBe('pics');
}, 5000);
test('GIVEN --subreddit is supplied, EXPECT subreddit to be changed', async () => {
const result = await cli(['--subreddit', 'pics'], '.');
const subreddit = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0] == 'Subreddit')!
.split(' = ')[1];
expect(subreddit).toBe('pics');
}, 5000);
});
describe('json', () => {
test('GIVEN -j is supplied, EXPECT output to be valid JSON', async () => {
const result = await cli(['-j'], '.');
const json = JSON.parse(result.stdout);
expect(json).toBeDefined();
}, 5000);
test('GIVEN --json is supplied, EXPECT output to be valid JSON', async () => {
const result = await cli(['--json'], '.');
const json = JSON.parse(result.stdout);
expect(json).toBeDefined();
}, 5000);
});
describe('sort', () => {
test('GIVEN --sort is not supplied, EXPECT sort to be defaulted', async () => {
const result = await cli(['-q'], '.');
const sortBy = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0] == 'Query.Sort By')!
.split(' = ')[1];
expect(sortBy).toBe('hot');
}, 5000);
test('GIVEN --sort is supplied WITH a valid input, EXPECT sort to be used', async () => {
const result = await cli(['-q', '--sort', 'new'], '.');
const sortBy = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0] == 'Query.Sort By')!
.split(' = ')[1];
expect(sortBy).toBe('new');
}, 5000);
test('GIVEN --sort is supplied WITH an invalid input, EXPECT error', async () => {
const result = await cli(['-q', '--sort', 'invalid'], '.');
expect(result.code).toBe(1);
expect(result.stderr).toBe("error: option '--sort <sort>' argument 'invalid' is invalid. Allowed choices are hot, new, top.\n");
}, 5000);
});
describe('query-metadata', () => {
test('GIVEN --query-metadata is not supplied, EXPECT no query metadata returned', async () => {
const result = await cli([], '.');
const query = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0].startsWith('Query'));
expect(query).toBeUndefined();
}, 5000);
test('GIVEN --query-metadata is supplied, EXPECT query metadata returned', async () => {
const result = await cli(['--query-metadata'], '.');
const query = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0].startsWith('Query'));
expect(query).toBeDefined();
}, 5000);
test('GIVEN -q is supplied, EXPECT query metadata returned', async () => {
const result = await cli(['-q'], '.');
const query = result.stdout.split('\n')
.find(x => x && x.length > 0 && x.split(' = ')[0].startsWith('Query'));
expect(query).toBeDefined();
}, 5000);
});
function cli(args: string[], cwd: string): Promise<cliResult> {
return new Promise(resolve => {
exec(`node ${path.resolve('./dist/cli.js')} ${args.join(' ')}`,
{ cwd },
(error, stdout, stderr) => { resolve({
code: error && error.code ? error.code : 0,
error,
stdout,
stderr });
});
});
}
interface cliResult {
code: number,
error: any,
stdout: string,
stderr: string,
}

View file

@ -1,5 +1,3 @@
import { ErrorCode } from "../src/constants/ErrorCode";
import ErrorMessages from "../src/constants/ErrorMessages";
import ImageHelper from "../src/imageHelper"; import ImageHelper from "../src/imageHelper";
import randomBunny from "../src/index"; import randomBunny from "../src/index";
import fetch from "got-cjs"; import fetch from "got-cjs";
@ -35,7 +33,6 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeTruthy(); expect(result.IsSuccess).toBeTruthy();
expect(result.Result).toBeDefined(); expect(result.Result).toBeDefined();
expect(result.Error).toBeUndefined();
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
@ -67,7 +64,6 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeTruthy(); expect(result.IsSuccess).toBeTruthy();
expect(result.Result).toBeDefined(); expect(result.Result).toBeDefined();
expect(result.Error).toBeUndefined();
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/hot.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/hot.json?limit=100');
}); });
@ -99,22 +95,17 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeTruthy(); expect(result.IsSuccess).toBeTruthy();
expect(result.Result).toBeDefined(); expect(result.Result).toBeDefined();
expect(result.Error).toBeUndefined();
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/hot.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/hot.json?limit=100');
}); });
test('GIVEN the fetch fails, EXPECT failure result', async () => { test('GIVEN the fetch fails, EXPECT failure result', async () => {
fetchMock.mockRejectedValue('Test Reason') fetchMock.mockResolvedValue(null);
const result = await randomBunny('rabbits', 'new'); const result = await randomBunny('rabbits', 'new');
expect(result.IsSuccess).toBeFalsy(); expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined(); expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.FailedToFetchReddit);
expect(result.Error!.Message).toBe(ErrorMessages.FailedToFetchReddit);
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
@ -128,10 +119,6 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeFalsy(); expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined(); expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.UnableToParseJSON);
expect(result.Error!.Message).toBe(ErrorMessages.UnableToParseJSON);
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
@ -149,10 +136,6 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeFalsy(); expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined(); expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.NoImageResultsFound);
expect(result.Error!.Message).toBe(ErrorMessages.NoImageResultsFound);
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
@ -184,12 +167,7 @@ describe('randomBunny', () => {
expect(result.IsSuccess).toBeFalsy(); expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined(); expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.NoImageResultsFound);
expect(result.Error!.Message).toBe(ErrorMessages.NoImageResultsFound);
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
@ -226,7 +204,7 @@ describe('randomBunny', () => {
expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledTimes(1); expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledTimes(1);
expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledWith("https://i.redd.it/gallery/cr8xudsnkgua1"); expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledWith("https://i.redd.it/gallery/cr8xudsnkgua1")
}); });
test("GIVEN data fetched is a gallery AND an image is not returned from the helper, EXPECT error", async () => { test("GIVEN data fetched is a gallery AND an image is not returned from the helper, EXPECT error", async () => {
@ -259,8 +237,5 @@ describe('randomBunny', () => {
expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledTimes(1); expect(ImageHelper.FetchImageFromRedditGallery).toHaveBeenCalledTimes(1);
expect(result.IsSuccess).toBe(false); expect(result.IsSuccess).toBe(false);
expect(result.Error).toBeDefined();
expect(result.Error?.Code).toBe(ErrorCode.NoImageResultsFound);
expect(result.Error?.Message).toBe(ErrorMessages.NoImageResultsFound);
}); });
}); });

3350
yarn.lock

File diff suppressed because it is too large Load diff