diff --git a/config/webpack.common.js b/config/webpack.common.js index 63d1298..cf528a9 100644 --- a/config/webpack.common.js +++ b/config/webpack.common.js @@ -5,55 +5,47 @@ var ExtractTextPlugin = require('extract-text-webpack-plugin'); var helpers = require('./helpers'); module.exports = { - entry: { - 'main': './src/app/main.tsx', - 'vendor': './src/app/vendor.ts' - }, - - resolve: { - extensions: ['', '.js', '.ts', '.tsx'] - }, - - module: { - loaders: [ - { test: /\.tsx?$/, loader: "ts-loader" }, - { - test: /\.html$/, - loader: 'html' - }, - { - test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, - loader: 'file?name=public/[name].[hash].[ext]' - } - ], - preLoaders: [ - // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. - { test: /\.js$/, loader: "source-map-loader" } + + resolve: { + extensions: ['', '.js', '.ts', '.tsx'] + }, + + module: { + loaders: [ + { test: /\.tsx?$/, loaders: ["react-hot-loader/webpack", "ts-loader"] }, + { + test: /\.html$/, + loader: 'html' + }, + { + test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, + loader: 'file?name=public/[name].[hash].[ext]' + } + ], + preLoaders: [ + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + { test: /\.js$/, loader: "source-map-loader" } + ] + }, + + plugins: [ + new webpack.optimize.CommonsChunkPlugin({ + name: ['main', 'vendor'] + }), + + new HtmlWebpackPlugin({ + template: './src/index.html', + filename: 'index.html' + }), + + new CopyWebpackPlugin( + [{ + from: './src/public', + to: 'public' + }] + ), + + new webpack.ProvidePlugin({}), + ] - }, - - plugins: [ - new webpack.optimize.CommonsChunkPlugin({ - name: ['main', 'vendor'] - }), - - new HtmlWebpackPlugin({ - template: './src/index.html', - filename: 'index.html' - }), - - new CopyWebpackPlugin( - [ - { - from: './src/public', - to: 'public' - } - ] - ), - - new webpack.ProvidePlugin({ - 'Promise': "bluebird" - }), - - ] -}; +}; \ No newline at end of file diff --git a/config/webpack.dev.js b/config/webpack.dev.js index f77dd1e..3a714ef 100644 --- a/config/webpack.dev.js +++ b/config/webpack.dev.js @@ -6,6 +6,14 @@ var helpers = require('./helpers'); module.exports = webpackMerge(commonConfig, { devtool: 'cheap-module-eval-source-map', + entry: { + // Add the react hot loader entry point - in reality, you only want this in your dev Webpack config + 'hot' :'react-hot-loader/patch', + 'hotserver' :'webpack/hot/only-dev-server', + 'main': './src/app/main.tsx', + 'vendor': './src/app/vendor.ts', + }, + output: { path: helpers.root('dist'), publicPath: 'http://localhost:3004/', diff --git a/config/webpack.prod.js b/config/webpack.prod.js index 1ff231e..0388977 100644 --- a/config/webpack.prod.js +++ b/config/webpack.prod.js @@ -9,6 +9,11 @@ const ENV = process.env.NODE_ENV = process.env.ENV = 'production'; module.exports = webpackMerge(commonConfig, { devtool: 'source-map', + entry: { + 'main': './src/app/main.tsx', + 'vendor': './src/app/vendor.ts' + }, + output: { path: helpers.root('dist'), publicPath: '/', diff --git a/package.json b/package.json index bd75d2b..a0b1bfc 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ }, "private": true, "dependencies": { - "bluebird": "^3.4.6", "body-parser": "^1.15.2", "bootstrap": "^3.3.7", "cheerio": "^0.22.0", + "core-js": "^2.4.1", "express": "^4.14.0", "express-graphql": "^0.5.3", "graphql": "^0.7.0", @@ -80,6 +80,7 @@ "mocha": "^3.0.2", "node-inspector": "^0.12.8", "nodemon": "^1.10.2", + "react-hot-loader": "^3.0.0-beta.6", "rimraf": "^2.5.4", "source-map-loader": "^0.1.5", "style-loader": "^0.13.1", diff --git a/src/app/components/findResult.tsx b/src/app/components/findResult.tsx new file mode 100644 index 0000000..e314d4b --- /dev/null +++ b/src/app/components/findResult.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import Movie from '../../models/movie'; +import Paper from 'material-ui/Paper'; +import Ratings from './ratings'; + +interface MovieDetailProps { + movie: Movie + showDetail: Function +} + +const isSmallScreen = typeof window !== 'undefined' && window.matchMedia("only screen and (max-width: 760px)").matches; +class FindResult extends React.Component { + constructor(props) { + super(props) + } + + private getSmallPosterSrc(posterUrl: string) { + return isSmallScreen ? posterUrl.replace('mpost', 'mpost4') : posterUrl; + } + + private showDetail(e) { + e.preventDefault(); + this.props.showDetail(this.props.movie); + } + + render() { + return ( + +
+ +
+
+
+ {this.props.movie.chineseTitle}({this.props.movie.englishTitle}) +
+ 上映日:{this.props.movie.releaseDate} + 類型:{this.props.movie.type} + 片長:{this.props.movie.runTime} +
+
+ +
+
+ 繼續閱讀... +
+
+
+ ); + }; +} + +export default FindResult; \ No newline at end of file diff --git a/src/app/components/home.tsx b/src/app/components/home.tsx index 1e1d043..673ae3a 100644 --- a/src/app/components/home.tsx +++ b/src/app/components/home.tsx @@ -1,28 +1,31 @@ import * as React from 'react'; import MovieDetailTabs from './movieDetailTabs'; +import FindResult from './findResult'; import AutoComplete from 'material-ui/AutoComplete'; import Paper from 'material-ui/Paper'; import Movie from '../../models/movie'; import 'isomorphic-fetch'; - class Home extends React.Component { - allMoviesName: Array = []; - resultMovie: any = {}; constructor(props) { super(props) this.state = { searchText: '', dataSource: [], - resultMovie: new Movie() + resultMovies: [] }; } componentWillMount() { - this.getDataSource(); + if (this.props.params.id){ + this.search([parseInt(this.props.params.id)]); + }else{ + + } } componentDidMount() { + this.getDataSource(); document.querySelector('input').focus(); } @@ -33,17 +36,11 @@ class Home extends React.Component { Accept: 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify({ query: "{allMovies{chineseTitle,englishTitle,yahooId}}" }), + body: JSON.stringify({ query: "{allMoviesNames{value,text}}" }), credentials: 'include', }).then(res => res.json()) .then(json => { - json.data.allMovies.forEach(({chineseTitle, englishTitle, yahooId}: Movie) => { - this.allMoviesName.push({ value: yahooId, text: chineseTitle }) - if (englishTitle && englishTitle !== chineseTitle) { - this.allMoviesName.push({ value: yahooId, text: englishTitle }) - } - }); - this.setState({ dataSource: this.allMoviesName }) + this.setState({ dataSource: json.data.allMoviesNames }) }); } @@ -54,7 +51,23 @@ class Home extends React.Component { document.querySelector('input').focus(); } - private search(selectItem, index) { + private onNewRequest(selectItem, index, filteredList) { + let yahooIds = []; + if (index === -1) { + let searchText = selectItem.toLowerCase(); + if (!filteredList) { + yahooIds = this.state.dataSource.filter(({value, text}) => text.toLowerCase().indexOf(searchText) !== -1).map(({value}) => parseInt(value)).slice(0, 6); + } else { + yahooIds = filteredList.map(({value}) => parseInt(value.key)).slice(0, 6); + } + } else { + yahooIds.push(parseInt(selectItem.value)); + } + + this.search(yahooIds); + } + + private search(yahooIds: Array) { fetch('/graphql', { method: 'POST', headers: { @@ -64,7 +77,7 @@ class Home extends React.Component { body: JSON.stringify({ query: ` { - movie(yahooId:${selectItem.value}){ + movies(yahooIds:${JSON.stringify(yahooIds)}){ yahooId posterUrl chineseTitle @@ -90,8 +103,7 @@ class Home extends React.Component { credentials: 'include', }).then(res => res.json()) .then(json => { - this.setState({ resultMovie: this.classifyArticle(json.data.movie) }); - document.querySelector('input').focus(); + this.setState({ resultMovies: json.data.movies.map(movie => this.classifyArticle(movie)) }); }); } @@ -117,11 +129,15 @@ class Home extends React.Component { return movie; } + private showDetail(movie) { + this.setState({ resultMovies: [movie] }); + } + render() { return (
-
+
{ fullWidth={true} filter={AutoComplete.caseInsensitiveFilter} maxSearchResults={6} - onNewRequest={this.search.bind(this)} + onNewRequest={this.onNewRequest.bind(this)} searchText={this.state.searchText} onUpdateInput={this.handleUpdateInput.bind(this)} />
- - - + { + this.state.resultMovies.length === 1 ? + + + : + this.state.resultMovies.map((movie: Movie) => ( + + )) + }
); } diff --git a/src/app/components/movieDetail.tsx b/src/app/components/movieDetail.tsx index b00f68d..3f711cf 100644 --- a/src/app/components/movieDetail.tsx +++ b/src/app/components/movieDetail.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import Movie from '../../models/movie'; +import Ratings from './ratings'; interface MovieDetailProps { movie: Movie @@ -14,28 +15,8 @@ class MovieDetail extends React.Component { render() { return (
-
-
-
- {this.props.movie.imdbID ? {this.props.movie.imdbRating ? this.props.movie.imdbRating : 'N/A'} - : {this.props.movie.imdbRating ? this.props.movie.imdbRating : 'N/A'} - } -
- -
- {this.props.movie.tomatoURL && this.props.movie.tomatoURL !== 'N/A' ? {this.props.movie.tomatoRating ? this.props.movie.tomatoRating : 'N/A'} - : {this.props.movie.tomatoRating ? this.props.movie.tomatoRating : 'N/A'} - } -
-
PTT - - {this.props.movie.goodRateArticles.length}/{this.props.movie.normalRateArticles.length}/{this.props.movie.badRateArticles.length} - -
-
- +
+ diff --git a/src/app/components/pttArticles.tsx b/src/app/components/pttArticles.tsx index e00c1bb..1b3b6d7 100644 --- a/src/app/components/pttArticles.tsx +++ b/src/app/components/pttArticles.tsx @@ -33,34 +33,31 @@ class PttArticles extends React.Component { {articleList.map((article: Article) => { return {article.push}} primaryText={{article.title}} secondaryText={
{article.date + ' ' + article.author}
} /> })}
- } render() { return ( -
- - - {this.getArticleList(this.props.movie.goodRateArticles)} - - - {this.getArticleList(this.props.movie.normalRateArticles)} - - - {this.getArticleList(this.props.movie.badRateArticles)} - - - {this.getArticleList(this.props.movie.otherArticles)} - - -
+ + + {this.getArticleList(this.props.movie.goodRateArticles)} + + + {this.getArticleList(this.props.movie.normalRateArticles)} + + + {this.getArticleList(this.props.movie.badRateArticles)} + + + {this.getArticleList(this.props.movie.otherArticles)} + + ); }; } diff --git a/src/app/components/ratings.tsx b/src/app/components/ratings.tsx new file mode 100644 index 0000000..3c0a49d --- /dev/null +++ b/src/app/components/ratings.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import Movie from '../../models/movie'; + +interface MovieDetailProps { + movie: Movie + className?: string +} + +class Ratings extends React.Component { + constructor(props) { + super(props) + } + + render() { + return ( +
+
+ {this.props.movie.imdbID ? {this.props.movie.imdbRating ? this.props.movie.imdbRating : 'N/A'} + : {this.props.movie.imdbRating ? this.props.movie.imdbRating : 'N/A'} + } +
+ +
+ {this.props.movie.tomatoURL && this.props.movie.tomatoURL !== 'N/A' ? {this.props.movie.tomatoRating ? this.props.movie.tomatoRating : 'N/A'} + : {this.props.movie.tomatoRating ? this.props.movie.tomatoRating : 'N/A'} + } +
+
PTT + + {this.props.movie.goodRateArticles.length}/{this.props.movie.normalRateArticles.length}/{this.props.movie.badRateArticles.length} + +
+
+ ); + }; +} + +export default Ratings; \ No newline at end of file diff --git a/src/app/main.css b/src/app/main.css index 3884421..b6bff13 100644 --- a/src/app/main.css +++ b/src/app/main.css @@ -2,10 +2,26 @@ html, body { height: 100%; width: 100%; margin: 0; } +@media (min-width: 992px) { + /*prevent scrollbar vibarate content */ + body { + width: calc(100vw - 34px); + } +} + div * { font-family: Noto Sans TC, Sans-Serif; } +.autoCompleteWrapper { + position: relative; +} + +input::-ms-clear { + width : 0; + height: 0; +} + .clearButton { cursor: pointer; background-color: inherit; @@ -17,12 +33,16 @@ div * { left: 100%; margin-left: -35px; outline: none; - color: #26C6DA + color: #26C6DA; + display: none; } -@media (min-width: 768px) { +@media (max-width: 768px) { .clearButton { - display: none; + display: block; + } + .autoCompleteWrapper { + margin-top: -.8em; } } @@ -64,6 +84,10 @@ div * { padding-right: 1em; } +.ratingWrapper>img, .ratingWrapper>pttLogo{ + margin-right: .2em; +} + @media (max-width: 992px) { .ratings { text-align: center; @@ -96,4 +120,56 @@ a.pttArticleTitle { a.pttArticleTitle:visited { color: #888 !important; +} + +.pttArticles::before{ + content: ""; + position: fixed; + top:0px; + bottom: 0; + background-color: black; + width: 100%; + z-index: -1; +} + +.no-padding { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.no-margin { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.resultSummary { + overflow: hidden; + max-height: 150px; + padding-top: .5em; +} + +.resultInfo>span{ + padding-right: 1em +} + +@media (max-width: 768px) { + .resultRatings .ratingWrapper>img{ + width:20px; + margin-right: .1em; + } + .resultRatings .pttLogo { + padding: 1px 2px; + margin-right: .1em; + } + .resultInfo>span{ + padding-right: .5em + } + .container, [class*="col-"] { + padding-left: .5em; + padding-right: .5em; + } +} + +.pointer { + cursor: pointer; } \ No newline at end of file diff --git a/src/app/main.tsx b/src/app/main.tsx index f246e1e..2105e1f 100644 --- a/src/app/main.tsx +++ b/src/app/main.tsx @@ -1,10 +1,24 @@ import * as React from 'react'; -import {Router} from 'react-router'; +import { Router } from 'react-router'; import * as ReactDOM from 'react-dom'; import createBrowserHistory from 'history/lib/createBrowserHistory'; import routes from './routes'; import './main.css'; -let history = createBrowserHistory(); +class Root extends React.Component { + render() { + return ( + {routes} + ); + } +} + +const rootElement = document.getElementById('app'); +ReactDOM.render(, rootElement); + +//for hot module reload +declare var module; +if (module.hot) { + module.hot.accept(); +} -ReactDOM.render({routes}, document.getElementById('app')); \ No newline at end of file diff --git a/src/app/routes.tsx b/src/app/routes.tsx index 85c80bd..b371c2d 100644 --- a/src/app/routes.tsx +++ b/src/app/routes.tsx @@ -5,6 +5,8 @@ import Home from './components/home'; export default ( - + + + ); \ No newline at end of file diff --git a/src/app/vendor.ts b/src/app/vendor.ts index 6e0f4c9..16d5f5f 100644 --- a/src/app/vendor.ts +++ b/src/app/vendor.ts @@ -1,10 +1,10 @@ +import 'core-js'; import 'material-ui'; import 'react'; import 'react-router'; import 'react-dom'; - //css import 'bootstrap/dist/css/bootstrap.min.css' import 'hint.css/hint.min.css' \ No newline at end of file diff --git a/src/crawler/imdbCrawler.ts b/src/crawler/imdbCrawler.ts index 23fcf9d..35189fa 100644 --- a/src/crawler/imdbCrawler.ts +++ b/src/crawler/imdbCrawler.ts @@ -40,8 +40,8 @@ export function filterNeedCrawlMovie({englishTitle, imdbRating, releaseDate, imd return shouldCrawl; } -function getImdbMovieInfo({englishTitle, yahooId}: Movie) { - return fetch(`${omdbApiUrl}?t=${encodeURIComponent(englishTitle)}&tomatoes=true&r=json`) +function getImdbMovieInfo({englishTitle, yahooId, releaseDate}: Movie) { + return fetch(`${omdbApiUrl}?t=${encodeURIComponent(englishTitle)}&y=${releaseDate.substr(0,4)}&tomatoes=true&r=json`) .then(res => { return res.json() }) .then(json => { var defer = Q.defer(); diff --git a/src/crawler/yahooInTheaterCrawler.ts b/src/crawler/yahooInTheaterCrawler.ts new file mode 100644 index 0000000..c51e547 --- /dev/null +++ b/src/crawler/yahooInTheaterCrawler.ts @@ -0,0 +1,26 @@ +import * as request from "request"; +import * as cheerio from "cheerio"; +import {db} from "../data/db"; +import * as Q from "q"; +import YahooMovie from '../models/yahooMovie'; + +const inTheaterUrl = 'https://tw.movies.yahoo.com/movie_intheaters.html'; +export function crawlInTheater() { + const defer = Q.defer(); + var req = request({ url: inTheaterUrl, followRedirect: false }, (error, res, body) => { + if (error) { + let reason = `error occur when request ${inTheaterUrl}, error:${error}`; + return defer.reject(reason); + } + + if (res.headers.location) { + let reason = `${inTheaterUrl} 404 not found`; + return defer.reject(reason); + } + + const $ = cheerio.load(body); + let yahooIds = $('.group h4>a').map((index,ele)=>$(ele).attr('href').split('id=')[1]) + return defer.resolve(yahooIds); + }) + return defer.promise; +} \ No newline at end of file diff --git a/src/data/cacheManager.ts b/src/data/cacheManager.ts index b5c4901..6aaf04b 100644 --- a/src/data/cacheManager.ts +++ b/src/data/cacheManager.ts @@ -2,23 +2,63 @@ import * as memoryCache from 'memory-cache'; import { db } from "../data/db"; import * as Q from "q"; import { mergeData } from '../crawler/mergeData'; +import * as moment from 'moment'; +import Movie from '../models/movie'; + export default class cacheManager { - static cacheKey = 'allMovies'; + static All_MOVIES = 'allMovies'; + static All_MOVIES_NAMES = 'allMoviesNames'; + static RECENT_MOVIES = 'recentMovies'; static init() { console.time('get yahooMovies and pttPages'); - return Q.spread([db.getCollection("yahooMovies", { yahooId: -1 }), + return Q.spread([db.getCollection("yahooMovies", { yahooId: 1 }), db.getCollection("pttPages", { pageIndex: -1 })], function (yahooMovies, pttPages) { console.timeEnd('get yahooMovies and pttPages'); - memoryCache.put(cacheManager.cacheKey, yahooMovies); - console.time('mergeData'); - let mergedDatas = mergeData(yahooMovies, pttPages); - console.timeEnd('mergeData'); - return memoryCache.put(cacheManager.cacheKey, mergedDatas); + cacheManager.setRecentMoviesCache(yahooMovies); + cacheManager.setAllMoviesNamesCache(yahooMovies); + cacheManager.setAllMoviesCache(yahooMovies, pttPages); + return; }); } + private static setRecentMoviesCache(yahooMovies: Array) { + let twoMonthsBeforeNow = moment().subtract(2, 'months'); + let now = moment(); + console.time('setRecentMoviesCache'); + let recentMovies = yahooMovies.filter(({releaseDate}) => { + return moment(releaseDate).isBetween(twoMonthsBeforeNow, now); + }); + memoryCache.put(cacheManager.RECENT_MOVIES, recentMovies); + console.timeEnd('setRecentMoviesCache'); + } + + private static setAllMoviesNamesCache(yahooMovies: Array) { + let allMoviesName = []; + let threeWeeksAfterNow = moment().add(21, 'days'); + console.time('setAllMoviesNamesCache'); + yahooMovies.forEach(({chineseTitle, englishTitle, yahooId, releaseDate}) => { + let isFarInFuture = moment(releaseDate).isAfter(threeWeeksAfterNow); + if (chineseTitle) { + isFarInFuture ? allMoviesName.push({ value: yahooId, text: chineseTitle }) : allMoviesName.unshift({ value: yahooId, text: chineseTitle }); + } + if (englishTitle && englishTitle !== chineseTitle) { + isFarInFuture ? allMoviesName.push({ value: yahooId, text: englishTitle }) : allMoviesName.unshift({ value: yahooId, text: englishTitle }); + } + }); + + memoryCache.put(cacheManager.All_MOVIES_NAMES, allMoviesName); + console.timeEnd('setAllMoviesNamesCache'); + } + + private static setAllMoviesCache(yahooMovies, pttPages) { + console.time('mergeData'); + let mergedDatas = mergeData(yahooMovies, pttPages); + console.timeEnd('mergeData'); + memoryCache.put(cacheManager.All_MOVIES, mergedDatas); + } + static get(key) { let data = memoryCache.get(key); return data; diff --git a/src/data/schema.ts b/src/data/schema.ts index 24682c0..36f7916 100644 --- a/src/data/schema.ts +++ b/src/data/schema.ts @@ -139,6 +139,20 @@ const MovieType = new GraphQLObjectType({ }) }); +const autoCompleteType = new GraphQLObjectType({ + name: "autoCompleteType", + fields: () => ({ + value: { + type: GraphQLString, + resolve: obj => obj.value, + }, + text: { + type: GraphQLString, + resolve: obj => obj.text, + }, + }) +}) + const QueryType = new GraphQLObjectType({ name: 'Query', description: 'query...', @@ -150,15 +164,21 @@ const QueryType = new GraphQLObjectType({ }, movie: { type: MovieType, + description: "[deprecated] query single movie, please use movies(yahooIds) instead", args: { yahooId: { type: GraphQLInt } }, resolve: (root, {yahooId, chineseTitle}) => { - let allMovies = cacheManager.get("allMovies"); + let allMovies = cacheManager.get(cacheManager.All_MOVIES); return allMovies.find((movie) => { return movie.yahooId === yahooId; }) }, }, - movieList: { + allMoviesNames: { + type: new GraphQLList(autoCompleteType), + description: 'Array of movie names, key:yahooId, value:chineseTitle or englishTitles', + resolve: (root, args) => cacheManager.get(cacheManager.All_MOVIES_NAMES) + }, + movies: { type: new GraphQLList(MovieType), args: { yahooIds: { type: new GraphQLList(GraphQLInt) } @@ -167,13 +187,18 @@ const QueryType = new GraphQLObjectType({ let allMovies: Array = cacheManager.get("allMovies"); let result = []; allMovies.forEach((movie) => { - if (yahooIds.indexOf(movie.yahooId)!==-1) { + if (yahooIds.indexOf(movie.yahooId) !== -1) { result.push(movie); } }) return result; }, }, + recentMovies: { + type: new GraphQLList(MovieType), + description: 'recent movies', + resolve: (root, args) => cacheManager.get(cacheManager.RECENT_MOVIES) + }, }), }); diff --git a/src/test/cacheManager.test.ts b/src/test/cacheManager.test.ts index 1feff3b..63b4372 100644 --- a/src/test/cacheManager.test.ts +++ b/src/test/cacheManager.test.ts @@ -15,7 +15,7 @@ chai.use(chaiAsPromised); class mockCacheManager extends cacheManager { static init() { let defer = Q.defer(); - memoryCache.put(cacheManager.cacheKey, [1]); + memoryCache.put(cacheManager.All_MOVIES, [1]); defer.resolve(); return defer.promise; } @@ -30,7 +30,7 @@ describe('cacheManager', () => { describe('get', () => { it('cacheManager', function () { - return mockCacheManager.get(cacheManager.cacheKey).should.have.length.above(0) + return mockCacheManager.get(cacheManager.All_MOVIES).should.have.length.above(0) }); }); }); \ No newline at end of file diff --git a/src/test/yahooInTheaterCrawler.test.ts b/src/test/yahooInTheaterCrawler.test.ts new file mode 100644 index 0000000..0175b32 --- /dev/null +++ b/src/test/yahooInTheaterCrawler.test.ts @@ -0,0 +1,23 @@ +import * as chai from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; +import { crawlInTheater } from '../crawler/yahooInTheaterCrawler'; +import { db } from "../data/db"; +import { systemSetting } from '../configs/systemSetting'; + + +const assert = chai.assert; +const expect = chai.expect; +const should = chai.should(); +chai.should(); +chai.use(chaiAsPromised); + + +describe('yahooInTheaterCrawler', () => { + before(() => { return db.openDbConnection(systemSetting.dbUrl) }) + describe('crawlInTheater.', () => { + it('should got yahooId list.', function () { + this.timeout(30000); + return crawlInTheater().should.eventually.have.length.above(0) + }); + }); +}); \ No newline at end of file