nekosia.js 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +18 -7
- package/types/tags.ts +1 -1
- package/examples/dynamicCategoryFetch.js +0 -16
- package/examples/fetchCategoryImages.js +0 -12
- package/examples/fetchImages.js +0 -12
- package/examples/fetchTags.js +0 -6
- package/examples/version.js +0 -8
- package/test/api.test.js +0 -134
- package/test/integration.test.js +0 -128
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nekosia.js",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "A simple wrapper for the Nekosia API that provides easy access to random anime images. Enrich your projects with a touch of anime magic and feline charm, meow~! Discover why switching to Nekosia is the purrfect choice! 💗",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anime",
|
|
@@ -45,8 +45,12 @@
|
|
|
45
45
|
"type": "git",
|
|
46
46
|
"url": "git+https://github.com/Nekosia-API/nekosia.js.git"
|
|
47
47
|
},
|
|
48
|
+
"funding": {
|
|
49
|
+
"type": "ko-fi",
|
|
50
|
+
"url": "https://ko-fi.com/nekosia"
|
|
51
|
+
},
|
|
48
52
|
"license": "MIT",
|
|
49
|
-
"author": "
|
|
53
|
+
"author": "Nekosia <support@nekosia.cat> (https://nekosia.cat)",
|
|
50
54
|
"type": "commonjs",
|
|
51
55
|
"main": "index.js",
|
|
52
56
|
"types": "types/index.d.ts",
|
|
@@ -54,13 +58,20 @@
|
|
|
54
58
|
"example": "examples",
|
|
55
59
|
"test": "test"
|
|
56
60
|
},
|
|
61
|
+
"files": [
|
|
62
|
+
"services",
|
|
63
|
+
"types",
|
|
64
|
+
"index.js",
|
|
65
|
+
"LICENSE",
|
|
66
|
+
"README.md"
|
|
67
|
+
],
|
|
57
68
|
"scripts": {
|
|
58
|
-
"
|
|
59
|
-
"
|
|
69
|
+
"m": "ncu -u && npm install && npm update",
|
|
70
|
+
"test": "jest"
|
|
60
71
|
},
|
|
61
72
|
"devDependencies": {
|
|
62
|
-
"@eslint/js": "^9.
|
|
63
|
-
"globals": "^16.
|
|
64
|
-
"jest": "^30.0
|
|
73
|
+
"@eslint/js": "^9.39.2",
|
|
74
|
+
"globals": "^16.5.0",
|
|
75
|
+
"jest": "^30.2.0"
|
|
65
76
|
}
|
|
66
77
|
}
|
package/types/tags.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export const TAGS =
|
|
2
|
-
['absolute-territory','after-the-rain','afternoon-tea','akazukin','alice-in-wonderland','alice-mana','
|
|
2
|
+
['absolute-territory','after-rain','after-the-rain','afternoon-tea','akazukin','alice-in-wonderland','alice-mana','alisso','alluring-face','alona','alone','amamine','amamineko-cafe','amashiro-natsuki','angel','angry-face','animal-ears','apex','apple','apple-caramel','apple-pie','apron-dress','aqua','aquarium','aria-tsukushi','arknights','armed-girls','armpits','assault-rifle','autumn','autumn-leaves','axillary-costume','azki','azkiart','azur-lane','babydoll','back-alley','back-of-thigh','background','balloon','balloons','bandages','bandaid','bare-feet','barefoot','basketball','basketball-uniform','beach','beautiful','beautiful-legs','beautiful-reimu','bed','bed-hair','bedroom','belly','belly-glimpse','bellybutton','bench','beret','bewitching-thighs','bikini','birthday','black-and-white','black-dress','black-hair','black-knee-high-socks','black-nail-polish','black-ribbon','black-sailor-uniform','black-shoes','black-skirt','black-stockings','black-thigh-high-socks','black-thigh-highs','black-tights','blazer','blonde','blonde-hair','bloomers','blue-archive','blue-eyes','blue-hair','blue-nail-polish','blue-ribbon','blue-shoes','blue-skirt','blue-sky','blushing','bocchi-chan','book','boots','botamochi','bottomless','boy-cut','braid','breasts','brown-eyes','brown-hair','brown-nail-polish','brown-skirt','bubble-tea','bunny-ears','bunny-girl','butterfly','by-the-window','cable-knitting','cafe','cake','camisole','camisole-dress','canal','candy-apple','car','cardigan','cardigan-uniform','casual-wear','cat-and-girl','cat-ears','cat-ears-hat','cat-ears-headband','cat-ears-headphones','cat-ears-hoodie','cat-ears-maid','cat-paws','cat-pose','cat-tail','catboy','catgirl','cats','cheeks','cherry','cherry-blossom','cherry-petals','chess','chibi','chihuahua','chin-resting','china-dress','chinese-lolita','chinese-style','chino','chino-kafuu','chitosezaka-suzu','chocolate','chocolate-cake','chocolate-mint','choker','christmas','chuuni','city','classroom','cloak','closed-eyes','clouds','cocoa-hoto','coffee','coffee-shop','collar','comic-treasure','confused','cookie','corset','cow-ears','cowgirl','crossed-legs','crying','cute','cute-cat','cuteness-is-justice','detexted','dog','dog-and-girl','dog-ears','doggirl','doll','donut','doujin','drawers','dress','dress-shirt','dvdart','elaina','elementary-school-student','elevator','epic-seven','eye-mask','eyepatch','fair-skin','fairy-eye','fairy-tale','fantasy','fantasy-girl','feather-ears','feet','feet-in-water','felicia-lulufleur','firefly','fireworks','fishnets','flare-skirt','flat-chest','floral-playing-cards','flower','flower-field','flowers','flowers-and-girls','food','footwear','forest','fox-ears','fox-mask','fox-shrine-maiden','foxgirl','frills','frostleaf','fubuki-shiragami','fubuki-shiragami-fanart','furina','fuwamoco','fuyoyo','fuzzy','game','game-pad','gamer','gamer-girl','garter','garterbelt','gawr-gura','gawrgura','genshin-impact','gensokyo-in-spring','getting-dressed','ghost','gijinka','girl','girls','glasses','gloves','gothic-lolita','gray-nail-polish','green-eyes','green-hair','green-nail-polish','green-ribbon','guitar','gun','gym-uniform','hair-tie-in-mouth','hairpin','hairstyle-change','hajime-todoroki','hakui-koyori','half-pants','half-pigtails','half-up-hairstyle','halloween','halo','hamico','han-costume','hanami','hands-forming-a-heart','happy','harness','haruhi-suzumiya','hatsune-miku','hayate-hisakawa','hazakura-chikori','headband','headboard-angle','headdress','headphone','headphones','headset','heart','heart-eyes','heartbreak','hearts','hedgehog','heels','herta','heterochromia','hibiki','hibiscus','high-angle','high-schoolgirl','high-waisted-skirt','hiiro','hikaru','hizamaru','holding-hands-with-fingers-interlocked','holding-ice-in-mouth','hololive','hololive-en','hololive-english','hololiveen','holox','hong','honkai-star-rail','hoodie','hoshi','hoshino','hoshizora-no-memoria','hot-spring','hu-tao','hutao','hydrangea','ice-cream','ichigo','ichigori-ena','idol','illumination','in-the-train','incredibly-cute','indie-vtuber','indoor-shoes','inner-color','inugami-korone','itigori-ena','jagged-sclera','japanese-maid','japanese-style','japanese-umbrella','jc','jellyfish','jk','jumper-skirt','jumpy','just-woke-up','kabashima-hana','kamiko-kana','kamisato-ayaka','kamiyama-shiki','kanade-otonose','kanon-mashiro','kantai-collection','karin','katana','kazari-rua','kazueru','kazusa-kyoyama','keqing','kimono','kimono-dress','kindergarten-pupil','kingdom','kirakira-monstars','kirara','kiryuu-kikyou','kitchen','klee','knee-high-socks','knitted-vest','koharu','koiko-irori','koito-amuno','korie-riko','koyori-hakui','koyori-sketch','kuda-izuna','kunoichi','kuro-namako','kuroneko','kuzunoha','kyaru','kyouyama-kazusa','lancat','lanmewko','laplus-darkness','large-breasts','large-food','leaning-forward','left-foot-shield','leggings','legs-in-water','lemon','leo','letter','lily-of-the-valley','lime','lingerie','little-devil','loafers','lollipop','long-black-hair','long-blonde-hair','long-brown-hair','long-hair','long-pink-hair','long-purple-hair','long-red-hair','long-silver-hair','long-white-gloves','long-white-hair','loungewear','love-letter','lying-down','lying-on-one-side','macaron','mad','magical-girl','magical-girl-witch-trials','maid','maid-uniform','makeup','mano-mackerel','mari-iochi','marie','marine-look','mascot','mayoi-shigure','melonpan','middle-school-student','midori-matsukaze','mihoshi-mei','miike-chan','mika','mika-misono','mikeneko','miko','minato-aqua','mini-hakama','miniskirt','miniskirt-miko','mint','mirror','mococo','mococo-abyssgard','moon','murasaki-shion','muryo','myoya','nachoneko','nagi-hisakawa','nahida','nail-polish','nana-kagura','nanashi-mumei','nap','natori-sana','necktie','negligee','nekoha-shizuku','nekomata-okayu','new-year','newsboy-cap','night','night-sky','nijisanji','nikke','nine-tailed','nintendo-switch','nintendoswitch','noire','nolan','nonaka-yuu','nurse','off-shoulder','one-eye-covered','one-piece','ookami-mio','orange-eyes','orange-hair','orange-nail-polish','orange-ribbon','otokonoko','overalls','overly-long-sleeves','painting','pajamas','pancake','panda-ears','parasol','park','patch','patting','peace-sign','pekora-usada-fanart','personification-of-drinks','petticoat','photo-editing','pigtails','pillow','pinching-garments','pink','pink-eyes','pink-hair','pink-nail-polish','pink-ribbon','pink-shoes','pink-skirt','pink-twintails','plaid-pattern','plaid-skirt','platform','playing-cards','plushie','pocky','pointy-ears','ponytail','porch','present','princess-connect','project-sekai','prone-position','purple-ears','purple-eyes','purple-hair','purple-nail-polish','purple-ribbon','purple-skirt','queen-of-hearts','railroad-crossing','railway','rain','raincoat','rainy-season','ramune','randoseru','rawr','red-and-blue','red-eyes','red-felt-cloth','red-hair','red-lacquered-umbrella','red-nail-polish','red-pigtails','red-ribbon','red-skirt','reflected-glare','regloss','reimu-hakurei','reisa-uzawa','remilia-scarlet','reverse-sitting','rhodes','ribbed-fabric','ribbon','ringo-chan','roar','rocket-launcher','rucaco','rumi','runa-shinomiya','rurudo','rurudo-lion','rushia-uruha','sad','saiba-midori','saiba-momoi','sailor-dress','sailor-one-piece','sailor-uniform','sakamata-chloe','sakura','sakura-miko','sakuraba-moeka','sakurada-hane','sakuradahane','sakurai-hana','santa','sassy-loli','scared','scarf','scenery','school-sweater','school-uniform','school-uniform-cardigan','school-uniform-hoodie','schoolgirl','scornful-eyes','sea','see-through','selfie','setokane','shano-hiyori','shanoa-asmr','shiba-inu','shigure','shiori','shirakawa-yumea','shirasu-azusa','shiroko','shiromichan','shooting-star','shopping','short-boots','short-hair','short-haircut','short-pants','short-white-hair','showgirl','shrunken-girl','shy','silver-hair','silver-long-hair','singer','sisters','sitting','skirt','skirt-lift','sleeping','sleepwear','sleepy','sleepy-face','sleeveless','sleeveless-dress','sleeveless-parka','small-fangs','smartphone','smile','smug-face','sneakers','snow','snowman','snowy-landscape','socks','sofa','sole','somna','sorasaki-hina','sousei','spiral-eyes','splashes','spring','squirrel','standing-picture','starlight-stage','starry-sky','starry-sky-dress','steamed-bun-with-meat-filling','stocking','straight-fringe','strap-shoes','straw-hat','strawberry','streaked-hair','striped-thigh-high-socks','summer','summer-dress','summer-kimono','summer-pockets','sunaookami-shiroko','sunflowers','sunohara-kokona','sunset','supine','suspender-skirt','suzuho-hotaru','suzutuki-sui','sweater','sweets','swimsuit','swimwear','swing','sword','tachibana-sherry','tail','tail-from-under-skirt','tail-holding','tail-with-ribbon','taiwan','takanashi','takanashi-hoshino','tea','tea-time','tears','teary-eyed','teddy-bear','telephone','the-person-behind','the-soles-of-feet-in-socks','thick-eyebrows','thigh-high-socks','thighs','three-colored-dumpling','tiered-dress','tiger','tight','tired','tobu-railway','toes','tongue-out','touhou','touhou-project','tropical-fish','twins','twintails','uise-iu','umbrella','underwater','uniform','upwards-gaze','usada-pekora','usagigo','valentine','vampire','varium','vocaloid','vrchat','vtuber','w-sitting','wa-lolita','waitress','wallpaper','wallpapers','water-surface','watermelon','weapon','wedding-dress','wet','what-is-this-cuteness','white-day','white-dress','white-hair','white-high-socks','white-knee-high-socks','white-long-hair','white-ribbon','white-sailor-uniform','white-skirt','white-socks','white-thigh-high-socks','white-tiger','white-tights','white-twintails','wings','wink','winter','witch','wolf','wolf-ears','wolfgirl','yandere','yaoyao','yawn','yellow-eyes','yellow-hair','yellow-nail-polish','yellow-ribbon','yoko','young-boy','young-girl','yuika-shiina','yuimisu','yukata','yukihana-lamy','yukinoshita-peo','yutori-natsu','yuuki-sakuna'];
|
|
3
3
|
|
|
4
4
|
// GET https://api.nekosia.cat/api/v1/tags
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const { NekosiaAPI } = require('../index.js');
|
|
2
|
-
|
|
3
|
-
const fetch = async (category, options = {}) => {
|
|
4
|
-
try {
|
|
5
|
-
const response = await NekosiaAPI.fetchCategoryImages(category, options);
|
|
6
|
-
console.log(`${category.toUpperCase()}:`, response);
|
|
7
|
-
} catch (err) {
|
|
8
|
-
console.error(`Error fetching ${category} images:`, err);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
(async () => {
|
|
13
|
-
await fetch('catgirl');
|
|
14
|
-
await fetch('foxgirl', { session: 'id', id: 'user123', count: 2 });
|
|
15
|
-
await fetch('catgirl', { tags: 'animal-ears' });
|
|
16
|
-
})();
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const { NekosiaAPI } = require('../index.js');
|
|
2
|
-
|
|
3
|
-
(async () => {
|
|
4
|
-
const response = await NekosiaAPI.fetchCategoryImages('foxgirl', {
|
|
5
|
-
session: 'ip',
|
|
6
|
-
count: 1,
|
|
7
|
-
additionalTags: ['cute', 'sakura', 'blue-hair', 'blue-eyes'],
|
|
8
|
-
blacklistedTags: ['beret', 'hat'],
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
console.log(response);
|
|
12
|
-
})();
|
package/examples/fetchImages.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const { NekosiaAPI } = require('../index.js');
|
|
2
|
-
|
|
3
|
-
(async () => {
|
|
4
|
-
const response = await NekosiaAPI.fetchImages({
|
|
5
|
-
session: 'ip',
|
|
6
|
-
count: 1,
|
|
7
|
-
tags: ['cute', 'sakura', 'blue-hair', 'blue-eyes'],
|
|
8
|
-
blacklist: ['beret', 'hat'],
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
console.log(response);
|
|
12
|
-
})();
|
package/examples/fetchTags.js
DELETED
package/examples/version.js
DELETED
package/test/api.test.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
const { NekosiaAPI } = require('../index.js');
|
|
2
|
-
|
|
3
|
-
const expectValidImageObject = res => {
|
|
4
|
-
expect(res.success).toBe(true);
|
|
5
|
-
expect(res.status).toBe(200);
|
|
6
|
-
expect(res).toHaveProperty('image');
|
|
7
|
-
expect(res.image.original.url).toEqual(expect.any(String));
|
|
8
|
-
expect(res.tags.length).toBeGreaterThan(0);
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
describe('nekosia.js tests', () => {
|
|
12
|
-
|
|
13
|
-
describe('fetchCategoryImages', () => {
|
|
14
|
-
|
|
15
|
-
it('should fetch one image when count is 1', async () => {
|
|
16
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
17
|
-
expectValidImageObject(res);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should fetch multiple images when count is between 2 and 24', async () => {
|
|
21
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 3 });
|
|
22
|
-
|
|
23
|
-
expect(res.success).toBe(true);
|
|
24
|
-
expect(res.status).toBe(200);
|
|
25
|
-
expect(Array.isArray(res.images)).toBe(true);
|
|
26
|
-
expect(res.images.length).toBe(3);
|
|
27
|
-
|
|
28
|
-
for (const img of res.images) {
|
|
29
|
-
expect(img).toHaveProperty('image');
|
|
30
|
-
expect(img.image.original.url).toEqual(expect.any(String));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should fetch maximum allowed number of images (20)', async () => {
|
|
35
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 20 });
|
|
36
|
-
|
|
37
|
-
expect(res.success).toBe(true);
|
|
38
|
-
expect(res.status).toBe(200);
|
|
39
|
-
expect(Array.isArray(res.images)).toBe(true);
|
|
40
|
-
expect(res.images.length).toBe(20);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should return error if count exceeds the maximum (999)', async () => {
|
|
44
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 999 });
|
|
45
|
-
|
|
46
|
-
expect(res.success).toBe(false);
|
|
47
|
-
expect(res.status).toBe(400);
|
|
48
|
-
expect(res.message).toMatch(/Count must be between 1 and/i);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should return error for invalid count value', async () => {
|
|
52
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 'invalid' });
|
|
53
|
-
expect(res.success).toBe(false);
|
|
54
|
-
expect(res.status).toBe(400);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should return error for negative count', async () => {
|
|
58
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: -5 });
|
|
59
|
-
expect(res.success).toBe(false);
|
|
60
|
-
expect(res.status).toBe(400);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should return error for count = 0', async () => {
|
|
64
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 0 });
|
|
65
|
-
expect(res.success).toBe(false);
|
|
66
|
-
expect(res.status).toBe(400);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should handle random category', async () => {
|
|
70
|
-
const res = await NekosiaAPI.fetchCategoryImages('random');
|
|
71
|
-
|
|
72
|
-
expectValidImageObject(res);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should return error for invalid category', async () => {
|
|
76
|
-
const res = await NekosiaAPI.fetchCategoryImages('invalid-category');
|
|
77
|
-
expect(res.success).toBe(false);
|
|
78
|
-
expect(res.status).toBe(400);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
describe('fetchImages', () => {
|
|
83
|
-
it('should return error when no image matches tags', async () => {
|
|
84
|
-
const res = await NekosiaAPI.fetchImages({
|
|
85
|
-
count: 1,
|
|
86
|
-
tags: ['invalid-tag1', 'invalid-tag2'],
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
expect(res.success).toBe(false);
|
|
90
|
-
expect(res.status).toBe(400);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should throw if tags array is empty', async () => {
|
|
94
|
-
await expect(() => NekosiaAPI.fetchImages({ tags: [] }))
|
|
95
|
-
.rejects
|
|
96
|
-
.toThrow('`tags` must be a non-empty array');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should return a valid image for known tag', async () => {
|
|
100
|
-
const res = await NekosiaAPI.fetchImages({
|
|
101
|
-
count: 1,
|
|
102
|
-
tags: ['catgirl'],
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
expectValidImageObject(res);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('fetchById', () => {
|
|
110
|
-
it('should fetch image by ID', async () => {
|
|
111
|
-
const preview = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
112
|
-
if (!preview.success || !preview.id) throw new Error('No valid image to fetch by ID');
|
|
113
|
-
|
|
114
|
-
const fetched = await NekosiaAPI.fetchById(preview.id);
|
|
115
|
-
expect(fetched.success).toBe(true);
|
|
116
|
-
expect(fetched.status).toBe(200);
|
|
117
|
-
expect(fetched.id).toBe(preview.id);
|
|
118
|
-
expect(fetched).toHaveProperty('image');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should return error for malformed ID', async () => {
|
|
122
|
-
const res = await NekosiaAPI.fetchById('12345');
|
|
123
|
-
expect(res.success).toBe(false);
|
|
124
|
-
expect(res.status).toBe(400);
|
|
125
|
-
expect(res.message).toMatch(/The image with the provided identifier was not found/);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should return error for valid format but non-existent ID', async () => {
|
|
129
|
-
const res = await NekosiaAPI.fetchById('keyboardcat');
|
|
130
|
-
expect(res.success).toBe(false);
|
|
131
|
-
expect(400).toBe(res.status);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
});
|
package/test/integration.test.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
const { NekosiaAPI } = require('../index.js');
|
|
2
|
-
const https = require('../services/https.js');
|
|
3
|
-
|
|
4
|
-
jest.mock('../services/https.js');
|
|
5
|
-
|
|
6
|
-
describe('NekosiaAPI', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
https.get.mockClear();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
describe('buildQueryParams', () => {
|
|
12
|
-
it('should correctly build query params', () => {
|
|
13
|
-
const options = { count: 3, additionalTags: ['tag1', 'tag2', 'tag3', 'tag4'], emptyValue: '', nullValue: null };
|
|
14
|
-
const result = NekosiaAPI.buildQueryParams(options);
|
|
15
|
-
expect(result).toBe('count=3&additionalTags=tag1%2Ctag2%2Ctag3%2Ctag4');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should return empty string for empty options', () => {
|
|
19
|
-
const result = NekosiaAPI.buildQueryParams({});
|
|
20
|
-
expect(result).toBe('');
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('makeHttpRequest', () => {
|
|
25
|
-
it('should make a successful HTTP request', async () => {
|
|
26
|
-
const mockResponse = { data: { results: [] } };
|
|
27
|
-
https.get.mockResolvedValue(mockResponse);
|
|
28
|
-
|
|
29
|
-
const endpoint = 'https://api.nekosia.cat/test-endpoint';
|
|
30
|
-
const res = await NekosiaAPI.makeHttpRequest(endpoint);
|
|
31
|
-
|
|
32
|
-
expect(res).toEqual(mockResponse);
|
|
33
|
-
expect(https.get).toHaveBeenCalledWith(endpoint);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should handle HTTP request errors', async () => {
|
|
37
|
-
const mockError = new Error('Request failed');
|
|
38
|
-
https.get.mockRejectedValue(mockError);
|
|
39
|
-
|
|
40
|
-
const endpoint = 'https://api.nekosia.cat/test-endpoint';
|
|
41
|
-
|
|
42
|
-
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
43
|
-
|
|
44
|
-
await expect(NekosiaAPI.makeHttpRequest(endpoint)).rejects.toThrow('Request failed');
|
|
45
|
-
expect(https.get).toHaveBeenCalledWith(endpoint);
|
|
46
|
-
|
|
47
|
-
consoleErrorSpy.mockRestore();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('fetchCategoryImages', () => {
|
|
52
|
-
it('should build correct endpoint and make request for given category', async () => {
|
|
53
|
-
const mockResponse = { data: { results: [] } };
|
|
54
|
-
https.get.mockResolvedValue(mockResponse);
|
|
55
|
-
|
|
56
|
-
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl?count=2&additionalTags=cute';
|
|
57
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 2, additionalTags: 'cute' });
|
|
58
|
-
|
|
59
|
-
expect(res).toEqual(mockResponse);
|
|
60
|
-
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should build correct endpoint with no query params if options are empty', async () => {
|
|
64
|
-
const mockResponse = { data: { results: [] } };
|
|
65
|
-
https.get.mockResolvedValue(mockResponse);
|
|
66
|
-
|
|
67
|
-
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl';
|
|
68
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl');
|
|
69
|
-
|
|
70
|
-
expect(res).toEqual(mockResponse);
|
|
71
|
-
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should include count=1 if explicitly set', async () => {
|
|
75
|
-
const mockResponse = { data: { results: [] } };
|
|
76
|
-
https.get.mockResolvedValue(mockResponse);
|
|
77
|
-
|
|
78
|
-
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl?count=1';
|
|
79
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
80
|
-
|
|
81
|
-
expect(res).toEqual(mockResponse);
|
|
82
|
-
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('fetchImages', () => {
|
|
88
|
-
it('should throw an error if tags is missing', async () => {
|
|
89
|
-
await expect(NekosiaAPI.fetchImages({})).rejects.toThrow('`tags` must be a non-empty array');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should throw an error if tags is not an array', async () => {
|
|
93
|
-
await expect(NekosiaAPI.fetchImages({ tags: 'not-an-array' }))
|
|
94
|
-
.rejects
|
|
95
|
-
.toThrow('`tags` must be a non-empty array');
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('should correctly call fetchImages with additionalTags', async () => {
|
|
99
|
-
const mockResponse = { data: { results: [] } };
|
|
100
|
-
https.get.mockResolvedValue(mockResponse);
|
|
101
|
-
|
|
102
|
-
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/nothing?count=1&additionalTags=dark%2Cshadow';
|
|
103
|
-
const res = await NekosiaAPI.fetchImages({ count: 1, tags: ['dark', 'shadow'] });
|
|
104
|
-
|
|
105
|
-
expect(res).toEqual(mockResponse);
|
|
106
|
-
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe('fetchById', () => {
|
|
111
|
-
it('should throw an error if id is missing or empty', async () => {
|
|
112
|
-
for (const id of [undefined, '']) {
|
|
113
|
-
await expect(NekosiaAPI.fetchById(id)).rejects.toThrow('`id` parameter is required');
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should correctly fetch image by ID', async () => {
|
|
118
|
-
const mockResponse = { data: { id: '123' } };
|
|
119
|
-
https.get.mockResolvedValue(mockResponse);
|
|
120
|
-
|
|
121
|
-
const id = '123';
|
|
122
|
-
const res = await NekosiaAPI.fetchById(id);
|
|
123
|
-
|
|
124
|
-
expect(res).toEqual(mockResponse);
|
|
125
|
-
expect(https.get).toHaveBeenCalledWith(`https://api.nekosia.cat/api/v1/getImageById/${id}`);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
});
|