@johndoeantler/mal-scraper
Version:
Scrap everything you can from MyAnimeList.net
219 lines (196 loc) • 6.47 kB
JavaScript
const test = require('ava')
const nock = require('nock')
const { getInfoFromName, getInfoFromURL, getResultsFromSearch } = require('../src')
const name = 'Sakura Trick'
const url = 'https://myanimelist.net/anime/20047/Sakura_Trick'
test.beforeEach(async t => {
await new Promise(resolve => setTimeout(resolve, 1500))
})
test('getInfoFromName returns null if no result - static tests', async t => {
// Static tests
nock('https://myanimelist.net')
.get('/search/prefix.json?type=anime&keyword=l')
.reply(200, { categories: [{ type: 'anime', items: [] }] })
try {
const data = await getInfoFromName('l')
t.is(data, null)
nock.cleanAll()
} catch (e) {
t.fail()
}
})
test('getInfoFromURL returns valid information for a novel', async t => {
try {
const data = await getInfoFromURL('https://myanimelist.net/manga/21479/Sword_Art_Online')
t.is(typeof data, 'object')
t.is(data.id, 21479)
t.is(data.title, 'Sword Art Online')
t.is(data.englishTitle, 'Sword Art Online')
t.is(data.japaneseTitle, 'ソードアート・オンライン')
t.is(data.status, 'Publishing')
t.is(data.authors[0], 'BUNBUN')
t.is(data.authors[1], 'Kawahara, Reki')
t.is(data.type, 'Light Novel')
t.is(data.synonyms[0], 'S.A.O')
t.is(data.synonyms[1], 'SAO')
t.is(data.genres[0], 'Action')
t.is(data.genres[1], 'Adventure')
t.is(data.genres[2], 'Fantasy')
t.is(data.genres[3], 'Romance')
t.is(data.characters.length, 10)
t.not(data.characters[0].link, undefined)
t.not(data.characters[0].picture, undefined)
t.is(data.characters[0].name, 'Kirigaya, Kazuto')
t.is(data.characters[0].role, 'Main')
t.is(data.staff, undefined)
t.is(data.serialization, 'None')
t.not(data.synopsis, undefined)
t.not(data.picture, undefined)
t.not(data.score, undefined)
t.not(data.scoreStats, undefined)
t.not(data.ranked, undefined)
t.not(data.popularity, undefined)
t.not(data.members, undefined)
t.not(data.favorites, undefined)
} catch (e) {
t.fail()
}
})
test('getInfoFromURL returns valid information for an anime that has mix names', async t => {
try {
const data = await getInfoFromURL('https://myanimelist.net/anime/30654/Ansatsu_Kyoushitsu_2nd_Season')
t.is(typeof data, 'object')
t.is(data.id, 30654)
t.is(data.title, 'Ansatsu Kyoushitsu 2nd Season')
t.not(data.synopsis, undefined)
t.not(data.picture, undefined)
t.is(data.characters.length, 10)
t.not(data.characters[0].link, undefined)
t.not(data.characters[0].picture, undefined)
t.is(data.characters[0].name, 'Koro-sensei')
t.is(data.characters[0].role, 'Main')
t.is(data.staff.length, 4)
t.not(data.staff[0].link, undefined)
t.not(data.staff[0].picture, undefined)
t.is(data.staff[0].name, 'Cook, Justin')
t.is(data.staff[0].role, 'Producer')
t.not(data.trailer, undefined)
t.is(data.englishTitle, 'Assassination Classroom Second Season')
t.is(data.japaneseTitle, '暗殺教室 第2期')
t.is(data.synonyms[0], 'Ansatsu Kyoushitsu Season 2')
t.is(data.synonyms[1], 'Ansatsu Kyoushitsu Final Season')
t.is(data.type, 'TV')
t.is(data.episodes, '25')
t.is(data.aired, 'Jan 8, 2016 to Jul 1, 2016')
t.is(data.premiered, 'Winter 2016')
t.is(data.broadcast, 'Fridays at 01:25 (JST)')
t.is(data.producers.length, 7)
t.is(data.producers[0], 'Dentsu')
t.is(data.producers[1], 'Studio Hibari')
t.is(data.producers[2], 'Fuji TV')
t.is(data.studios[0], 'Lerche')
t.is(data.source, 'Manga')
t.is(data.duration, '23 min. per ep.')
t.is(data.status, 'Finished Airing')
t.is(data.rating, 'PG-13 - Teens 13 or older')
t.is(data.genres.length, 2)
t.is(data.genres[0], 'Action')
t.is(data.genres[1], 'Comedy')
t.not(data.score, undefined)
t.not(data.scoreStats, undefined)
t.not(data.ranked, undefined)
t.not(data.popularity, undefined)
t.not(data.members, undefined)
t.not(data.favorites, undefined)
} catch (e) {
t.fail()
}
})
test('getInfoFromURL returns an error if invalid url', async t => {
try {
await getInfoFromURL('hello')
} catch (e) {
e.message.includes('Invalid Url')
? t.pass()
: t.fail()
}
})
test('getInfoFromURL returns valid information', async t => {
try {
const data = await getInfoFromURL(url)
t.is(typeof data, 'object')
t.is(data.title, name)
t.is(data.characters.length, 10)
t.is(data.staff.length, 4)
t.is(data.status, 'Finished Airing')
t.is(data.studios[0], 'Studio Deen')
t.not(data.picture, undefined)
} catch (e) {
t.fail()
}
})
test('getInfoFromName returns an error if invalid name', async t => {
try {
await getInfoFromName()
} catch (e) {
e.message.includes('Invalid name')
? t.pass()
: t.fail()
}
})
test('getInfoFromName returns valid information', async t => {
try {
const data = await getInfoFromName(name)
t.is(typeof data, 'object')
t.is(data.title, name)
t.is(data.characters.length, 10)
t.is(data.staff.length, 4)
t.is(data.status, 'Finished Airing')
t.is(data.studios[0], 'Studio Deen')
} catch (e) {
t.fail()
}
})
test('getInfoFromName returns valid with not the best match', async t => {
try {
const data = await getInfoFromName(name, false)
t.is(typeof data, 'object')
t.is(data.title, name)
t.is(data.characters.length, 10)
t.is(data.staff.length, 4)
t.is(data.status, 'Finished Airing')
t.is(data.studios[0], 'Studio Deen')
} catch (e) {
t.fail()
}
})
test('getInfoFromName returns valid when best match gives no answer', async t => {
try {
const data = await getInfoFromName('gakkou gurashi', false)
t.is(typeof data, 'object')
t.is(data.title, 'Gakkougurashi!')
t.is(data.url, 'https://myanimelist.net/anime/24765/Gakkougurashi')
} catch (e) {
t.fail()
}
})
test('getResultsFromSearch returns an error if invalid keyword', async t => {
try {
await getResultsFromSearch()
} catch (e) {
e.message.includes('[Mal-Scraper]')
? t.pass()
: t.fail()
}
})
test('getResultsFromSearch returns a valid array', async t => {
try {
const data = await getResultsFromSearch(name)
t.is(typeof data, 'object')
t.is(data.length, 10)
t.is(data[0].name, name)
t.is(data[0].id, 20047)
} catch (e) {
t.fail()
}
})