Compare commits
No commits in common. "c600385fab6d90cc1458b88e0ccdb7270e96b4ea" and "8a726b386ed0d995de81ca7816f3b005a4a229bd" have entirely different histories.
c600385fab
...
8a726b386e
19 changed files with 1378 additions and 2656 deletions
75
.drone.yml
Normal file
75
.drone.yml
Normal 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
2
.gitignore
vendored
|
@ -1,6 +1,4 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
bin/
|
|
||||||
coverage/
|
coverage/
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
.DS_Store
|
|
|
@ -1,5 +1,5 @@
|
||||||
src/
|
app.ts
|
||||||
bin/
|
|
||||||
tests/
|
tests/
|
||||||
jest.config.cjs
|
jest.config.cjs
|
||||||
jest.setup.js
|
jest.setup.js
|
|
@ -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
9
app.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import randomBunny from "./dist/index.js";
|
||||||
|
|
||||||
|
async function app() {
|
||||||
|
const result = await randomBunny('rabbits', 'hot');
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
app();
|
97
docs/cli.md
97
docs/cli.md
|
@ -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
|
|
||||||
```
|
|
32
package.json
32
package.json
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
10
readme.md
10
readme.md
|
@ -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.
|
||||||
|
|
56
src/cli.ts
56
src/cli.ts
|
@ -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);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,6 +0,0 @@
|
||||||
export enum ErrorCode {
|
|
||||||
Unknown,
|
|
||||||
FailedToFetchReddit,
|
|
||||||
UnableToParseJSON,
|
|
||||||
NoImageResultsFound,
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
export default interface ICliOptions {
|
|
||||||
subreddit: string,
|
|
||||||
json?: boolean,
|
|
||||||
sort: string,
|
|
||||||
queryMetadata?: boolean,
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { ErrorCode } from "../constants/ErrorCode";
|
|
||||||
|
|
||||||
export default interface IError {
|
|
||||||
Code: ErrorCode;
|
|
||||||
Message: string;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
export default interface QueryResult {
|
|
||||||
subreddit: string,
|
|
||||||
sortBy: string,
|
|
||||||
}
|
|
60
src/index.ts
60
src/index.ts
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -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,
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
Loading…
Reference in a new issue