You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issues_controller_test.rb 259KB

Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
15 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006- Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. require_relative '../test_helper'
  19. class IssuesControllerTest < Redmine::ControllerTest
  20. fixtures :projects,
  21. :users, :email_addresses, :user_preferences,
  22. :roles,
  23. :members,
  24. :member_roles,
  25. :issues,
  26. :issue_statuses,
  27. :issue_relations,
  28. :versions,
  29. :trackers,
  30. :projects_trackers,
  31. :issue_categories,
  32. :enabled_modules,
  33. :enumerations,
  34. :attachments,
  35. :workflows,
  36. :custom_fields,
  37. :custom_values,
  38. :custom_fields_projects,
  39. :custom_fields_trackers,
  40. :time_entries,
  41. :journals,
  42. :journal_details,
  43. :queries,
  44. :repositories,
  45. :changesets,
  46. :watchers, :groups_users
  47. include Redmine::I18n
  48. def setup
  49. User.current = nil
  50. end
  51. def test_index
  52. with_settings :default_language => "en" do
  53. get :index
  54. assert_response :success
  55. # links to visible issues
  56. assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
  57. assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
  58. # private projects hidden
  59. assert_select 'a[href="/issues/6"]', 0
  60. assert_select 'a[href="/issues/4"]', 0
  61. # project column
  62. assert_select 'th', :text => /Project/
  63. end
  64. end
  65. def test_index_should_not_list_issues_when_module_disabled
  66. EnabledModule.where("name = 'issue_tracking' AND project_id = 1").delete_all
  67. get :index
  68. assert_response :success
  69. assert_select 'a[href="/issues/1"]', 0
  70. assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
  71. end
  72. def test_index_should_list_visible_issues_only
  73. get(:index, :params => {:per_page => 100})
  74. assert_response :success
  75. Issue.open.each do |issue|
  76. assert_select "tr#issue-#{issue.id}", issue.visible? ? 1 : 0
  77. end
  78. end
  79. def test_index_with_project
  80. with_settings :display_subprojects_issues => '0' do
  81. get(:index, :params => {:project_id => 1})
  82. assert_response :success
  83. # query form
  84. assert_select 'form#query_form' do
  85. assert_select 'div#query_form_with_buttons.hide-when-print' do
  86. assert_select 'div#query_form_content' do
  87. assert_select 'fieldset#filters.collapsible'
  88. assert_select 'fieldset#options'
  89. end
  90. assert_select 'p.buttons'
  91. end
  92. end
  93. assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
  94. assert_select 'a[href="/issues/5"]', 0
  95. end
  96. end
  97. def test_index_with_project_and_subprojects
  98. with_settings :display_subprojects_issues => '1' do
  99. get(:index, :params => {:project_id => 1})
  100. assert_response :success
  101. assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
  102. assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
  103. assert_select 'a[href="/issues/6"]', 0
  104. end
  105. end
  106. def test_index_should_list_issues_of_closed_subprojects
  107. @request.session[:user_id] = 1
  108. project = Project.find(1)
  109. with_settings :display_subprojects_issues => '1' do
  110. # One of subprojects is closed
  111. Project.find_by(:identifier => 'subproject1').close
  112. get(:index, :params => {:project_id => project.id})
  113. assert_response :success
  114. assert_equal 10, issues_in_list.count
  115. # All subprojects are closed
  116. project.descendants.each(&:close)
  117. get(:index, :params => {:project_id => project.id})
  118. assert_response :success
  119. assert_equal 10, issues_in_list.count
  120. end
  121. end
  122. def test_index_with_subproject_filter_should_not_exclude_closed_subprojects_issues
  123. subproject1 = Project.find(3)
  124. subproject2 = Project.find(4)
  125. subproject1.close
  126. with_settings :display_subprojects_issues => '1' do
  127. get(
  128. :index,
  129. :params => {
  130. :project_id => 1,
  131. :set_filter => 1,
  132. :f => ['subproject_id'],
  133. :op => {'subproject_id' => '!'},
  134. :v => {'subproject_id' => [subproject2.id.to_s]},
  135. :c => ['project']
  136. }
  137. )
  138. end
  139. assert_response :success
  140. column_values = columns_values_in_list('project')
  141. assert_includes column_values, subproject1.name
  142. assert_equal 9, column_values.size
  143. end
  144. def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
  145. @request.session[:user_id] = 2
  146. with_settings :display_subprojects_issues => '1' do
  147. get(:index, :params => {:project_id => 1})
  148. assert_response :success
  149. assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
  150. assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
  151. assert_select 'a[href="/issues/6"]', :text => /Issue of a private subproject/
  152. end
  153. end
  154. def test_index_with_project_and_default_filter
  155. get(
  156. :index,
  157. :params => {
  158. :project_id => 1,
  159. :set_filter => 1
  160. }
  161. )
  162. assert_response :success
  163. # default filter
  164. assert_query_filters [['status_id', 'o', '']]
  165. end
  166. def test_index_with_project_and_filter
  167. get(
  168. :index,
  169. :params => {
  170. :project_id => 1,
  171. :set_filter => 1,
  172. :f => ['tracker_id'],
  173. :op => {
  174. 'tracker_id' => '='
  175. },
  176. :v => {
  177. 'tracker_id' => ['1']
  178. }
  179. }
  180. )
  181. assert_response :success
  182. assert_query_filters [['tracker_id', '=', '1']]
  183. end
  184. def test_index_with_short_filters
  185. to_test = {
  186. 'status_id' => {
  187. 'o' => {:op => 'o', :values => ['']},
  188. 'c' => {:op => 'c', :values => ['']},
  189. '7' => {:op => '=', :values => ['7']},
  190. '7|3|4' => {:op => '=', :values => ['7', '3', '4']},
  191. '=7' => {:op => '=', :values => ['7']},
  192. '!3' => {:op => '!', :values => ['3']},
  193. '!7|3|4' => {:op => '!', :values => ['7', '3', '4']}
  194. },
  195. 'subject' => {
  196. 'This is a subject' => {:op => '=', :values => ['This is a subject']},
  197. 'o' => {:op => '=', :values => ['o']},
  198. '~This is part of a subject' => {:op => '~', :values => ['This is part of a subject']},
  199. '!~This is part of a subject' => {:op => '!~', :values => ['This is part of a subject']}
  200. },
  201. 'tracker_id' => {
  202. '3' => {:op => '=', :values => ['3']},
  203. '=3' => {:op => '=', :values => ['3']}
  204. },
  205. 'start_date' => {
  206. '2011-10-12' => {:op => '=', :values => ['2011-10-12']},
  207. '=2011-10-12' => {:op => '=', :values => ['2011-10-12']},
  208. '>=2011-10-12' => {:op => '>=', :values => ['2011-10-12']},
  209. '<=2011-10-12' => {:op => '<=', :values => ['2011-10-12']},
  210. '><2011-10-01|2011-10-30' => {:op => '><', :values => ['2011-10-01', '2011-10-30']},
  211. '<t+2' => {:op => '<t+', :values => ['2']},
  212. '>t+2' => {:op => '>t+', :values => ['2']},
  213. 't+2' => {:op => 't+', :values => ['2']},
  214. 't' => {:op => 't', :values => ['']},
  215. 'w' => {:op => 'w', :values => ['']},
  216. '>t-2' => {:op => '>t-', :values => ['2']},
  217. '<t-2' => {:op => '<t-', :values => ['2']},
  218. 't-2' => {:op => 't-', :values => ['2']}
  219. },
  220. 'created_on' => {
  221. '>=2011-10-12' => {:op => '>=', :values => ['2011-10-12']},
  222. '<t-2' => {:op => '<t-', :values => ['2']},
  223. '>t-2' => {:op => '>t-', :values => ['2']},
  224. 't-2' => {:op => 't-', :values => ['2']}
  225. },
  226. 'cf_1' => {
  227. 'c' => {:op => '=', :values => ['c']},
  228. '!c' => {:op => '!', :values => ['c']},
  229. '!*' => {:op => '!*', :values => ['']},
  230. '*' => {:op => '*', :values => ['']}
  231. },
  232. 'estimated_hours' => {
  233. '=13.4' => {:op => '=', :values => ['13.4']},
  234. '>=45' => {:op => '>=', :values => ['45']},
  235. '<=125' => {:op => '<=', :values => ['125']},
  236. '><10.5|20.5' => {:op => '><', :values => ['10.5', '20.5']},
  237. '!*' => {:op => '!*', :values => ['']},
  238. '*' => {:op => '*', :values => ['']}
  239. }
  240. }
  241. default_filter = {'status_id' => {:operator => 'o', :values => ['']}}
  242. to_test.each do |field, expression_and_expected|
  243. expression_and_expected.each do |filter_expression, expected|
  244. get(:index, :params => {:set_filter => 1, field => filter_expression})
  245. assert_response :success
  246. expected_with_default =
  247. default_filter.
  248. merge({field => {:operator => expected[:op], :values => expected[:values]}})
  249. assert_query_filters(
  250. expected_with_default.map {|f, v| [f, v[:operator], v[:values]]}
  251. )
  252. end
  253. end
  254. end
  255. def test_index_with_project_and_empty_filters
  256. get(
  257. :index,
  258. :params => {
  259. :project_id => 1,
  260. :set_filter => 1,
  261. :fields => ['']
  262. }
  263. )
  264. assert_response :success
  265. # no filter
  266. assert_query_filters []
  267. end
  268. def test_index_with_project_custom_field_filter
  269. field =
  270. ProjectCustomField.
  271. create!(:name => 'Client', :is_filter => true, :field_format => 'string')
  272. CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
  273. CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
  274. filter_name = "project.cf_#{field.id}"
  275. @request.session[:user_id] = 1
  276. get(
  277. :index,
  278. :params => {
  279. :set_filter => 1,
  280. :f => [filter_name],
  281. :op => {
  282. filter_name => '='
  283. },
  284. :v => {
  285. filter_name => ['Foo']
  286. },
  287. :c => ['project']
  288. }
  289. )
  290. assert_response :success
  291. assert_equal [3, 5], issues_in_list.map(&:project_id).uniq.sort
  292. end
  293. def test_index_with_project_status_filter
  294. project = Project.find(2)
  295. project.close
  296. project.save
  297. get(
  298. :index,
  299. :params => {
  300. :set_filter => 1,
  301. :f => ['project.status'],
  302. :op => {'project.status' => '='},
  303. :v => {'project.status' => ['1']}
  304. }
  305. )
  306. assert_response :success
  307. issues = issues_in_list.map(&:id).uniq.sort
  308. assert_include 1, issues
  309. assert_not_include 4, issues
  310. end
  311. def test_index_with_query
  312. get(
  313. :index,
  314. :params => {
  315. :project_id => 1,
  316. :query_id => 5
  317. }
  318. )
  319. assert_response :success
  320. assert_select '#sidebar .queries' do
  321. # assert only query is selected in sidebar
  322. assert_select 'a.query.selected', 1
  323. # assert link properties
  324. assert_select(
  325. 'a.query.selected[href=?]',
  326. '/projects/ecookbook/issues?query_id=5',
  327. :text => "Open issues by priority and tracker"
  328. )
  329. # assert only one clear link exists
  330. assert_select 'a.icon-clear-query', 1
  331. # assert clear link properties
  332. assert_select(
  333. 'a.icon-clear-query[title=?][href=?]',
  334. 'Clear',
  335. '/projects/ecookbook/issues?set_filter=1&sort=',
  336. 1
  337. )
  338. end
  339. end
  340. def test_index_with_query_grouped_by_tracker
  341. get(
  342. :index,
  343. :params => {
  344. :project_id => 1,
  345. :query_id => 6
  346. }
  347. )
  348. assert_response :success
  349. assert_select 'tr.group span.count'
  350. end
  351. def test_index_with_query_grouped_and_sorted_by_category
  352. get(
  353. :index,
  354. :params => {
  355. :project_id => 1,
  356. :set_filter => 1,
  357. :group_by => "category",
  358. :sort => "category"
  359. }
  360. )
  361. assert_response :success
  362. assert_select 'tr.group span.count'
  363. end
  364. def test_index_with_query_grouped_and_sorted_by_fixed_version
  365. get(
  366. :index,
  367. :params => {
  368. :project_id => 1,
  369. :set_filter => 1,
  370. :group_by => "fixed_version",
  371. :sort => "fixed_version"
  372. }
  373. )
  374. assert_response :success
  375. assert_select 'tr.group span.count'
  376. end
  377. def test_index_with_query_grouped_and_sorted_by_fixed_version_in_reverse_order
  378. get(
  379. :index,
  380. :params => {
  381. :project_id => 1,
  382. :set_filter => 1,
  383. :group_by => "fixed_version",
  384. :sort => "fixed_version:desc"
  385. }
  386. )
  387. assert_response :success
  388. assert_select 'tr.group span.count'
  389. end
  390. def test_index_grouped_by_due_date
  391. set_tmp_attachments_directory
  392. Issue.destroy_all
  393. Issue.generate!(:due_date => '2018-08-10')
  394. Issue.generate!(:due_date => '2018-08-10')
  395. Issue.generate!
  396. get(
  397. :index,
  398. :params => {
  399. :set_filter => 1,
  400. :group_by => "due_date"
  401. }
  402. )
  403. assert_response :success
  404. assert_select 'tr.group span.name', :value => '2018-08-10' do
  405. assert_select '~ span.count', :value => '2'
  406. end
  407. assert_select 'tr.group span.name', :value => '(blank)' do
  408. assert_select '~ span.count', :value => '1'
  409. end
  410. end
  411. def test_index_grouped_by_created_on_if_time_zone_is_utc
  412. # TODO: test fails with mysql
  413. skip if mysql?
  414. skip unless IssueQuery.new.groupable_columns.detect {|c| c.name == :created_on}
  415. @request.session[:user_id] = 2
  416. User.find(2).pref.update(time_zone: 'UTC')
  417. get(
  418. :index,
  419. :params => {
  420. :set_filter => 1,
  421. :group_by => 'created_on'
  422. }
  423. )
  424. assert_response :success
  425. assert_select 'tr.group span.name', :text => '07/19/2006' do
  426. assert_select '+ span.count', :text => '2'
  427. end
  428. end
  429. def test_index_grouped_by_created_on_if_time_zone_is_nil
  430. skip unless IssueQuery.new.groupable_columns.detect {|c| c.name == :created_on}
  431. current_user = User.find(2)
  432. @request.session[:user_id] = current_user.id
  433. current_user.pref.update(time_zone: nil)
  434. get(
  435. :index,
  436. :params => {
  437. :set_filter => 1,
  438. :group_by => 'created_on'
  439. }
  440. )
  441. assert_response :success
  442. # group_name depends on localtime
  443. group_name = format_date(Issue.second.created_on.localtime)
  444. assert_select 'tr.group span.name', :text => group_name do
  445. assert_select '+ span.count', :text => '2'
  446. end
  447. end
  448. def test_index_grouped_by_created_on_as_pdf
  449. skip unless IssueQuery.new.groupable_columns.detect {|c| c.name == :created_on}
  450. get(
  451. :index,
  452. :params => {
  453. :set_filter => 1,
  454. :group_by => 'created_on',
  455. :format => 'pdf'
  456. }
  457. )
  458. assert_response :success
  459. assert_equal 'application/pdf', response.media_type
  460. end
  461. def test_index_with_query_grouped_by_list_custom_field
  462. get(
  463. :index,
  464. :params => {
  465. :project_id => 1,
  466. :query_id => 9
  467. }
  468. )
  469. assert_response :success
  470. assert_select 'tr.group span.count'
  471. end
  472. def test_index_with_query_grouped_by_key_value_custom_field
  473. cf = IssueCustomField.
  474. create!(
  475. :name => 'Key',
  476. :is_for_all => true,
  477. :tracker_ids => [1, 2, 3],
  478. :field_format => 'enumeration'
  479. )
  480. cf.enumerations << valueb = CustomFieldEnumeration.new(:name => 'Value B', :position => 1)
  481. cf.enumerations << valuea = CustomFieldEnumeration.new(:name => 'Value A', :position => 2)
  482. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => valueb.id)
  483. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => valueb.id)
  484. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => valuea.id)
  485. CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
  486. get(
  487. :index,
  488. :params => {
  489. :project_id => 1,
  490. :set_filter => 1,
  491. :group_by => "cf_#{cf.id}"
  492. }
  493. )
  494. assert_response :success
  495. assert_select 'tr.group', 3
  496. assert_select 'tr.group' do
  497. assert_select 'span.name', :text => 'Value B'
  498. assert_select 'span.count', :text => '2'
  499. end
  500. assert_select 'tr.group' do
  501. assert_select 'span.name', :text => 'Value A'
  502. assert_select 'span.count', :text => '1'
  503. end
  504. end
  505. def test_index_with_query_grouped_by_user_custom_field
  506. cf = IssueCustomField.
  507. create!(
  508. :name => 'User',
  509. :is_for_all => true,
  510. :tracker_ids => [1, 2, 3],
  511. :field_format => 'user'
  512. )
  513. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
  514. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
  515. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
  516. CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
  517. get(
  518. :index,
  519. :params => {
  520. :project_id => 1,
  521. :set_filter => 1,
  522. :group_by => "cf_#{cf.id}"
  523. }
  524. )
  525. assert_response :success
  526. assert_select 'tr.group', 3
  527. assert_select 'tr.group' do
  528. assert_select 'a', :text => 'John Smith'
  529. assert_select 'span.count', :text => '1'
  530. end
  531. assert_select 'tr.group' do
  532. assert_select 'a', :text => 'Dave Lopper'
  533. assert_select 'span.count', :text => '2'
  534. end
  535. end
  536. def test_index_grouped_by_boolean_custom_field_should_distinguish_blank_and_false_values
  537. cf = IssueCustomField.
  538. create!(
  539. :name => 'Bool',
  540. :is_for_all => true,
  541. :tracker_ids => [1, 2, 3],
  542. :field_format => 'bool'
  543. )
  544. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '1')
  545. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
  546. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '')
  547. with_settings :default_language => 'en' do
  548. get(
  549. :index,
  550. :params => {
  551. :project_id => 1,
  552. :set_filter => 1,
  553. :group_by => "cf_#{cf.id}"
  554. }
  555. )
  556. assert_response :success
  557. end
  558. assert_select 'tr.group', 3
  559. assert_select 'tr.group', :text => /Yes/
  560. assert_select 'tr.group', :text => /No/
  561. assert_select 'tr.group', :text => /blank/
  562. end
  563. def test_index_grouped_by_boolean_custom_field_with_false_group_in_first_position_should_show_the_group
  564. cf = IssueCustomField.
  565. create!(
  566. :name => 'Bool',
  567. :is_for_all => true,
  568. :tracker_ids => [1, 2, 3],
  569. :field_format => 'bool',
  570. :is_filter => true
  571. )
  572. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '0')
  573. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
  574. with_settings :default_language => 'en' do
  575. get(
  576. :index,
  577. :params => {
  578. :project_id => 1,
  579. :set_filter => 1, "cf_#{cf.id}" => "*",
  580. :group_by => "cf_#{cf.id}"
  581. }
  582. )
  583. assert_response :success
  584. end
  585. assert_equal [1, 2], issues_in_list.map(&:id).sort
  586. assert_select 'tr.group', 1
  587. assert_select 'tr.group', :text => /No/
  588. end
  589. def test_index_with_query_grouped_by_tracker_in_normal_order
  590. 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
  591. get(
  592. :index,
  593. :params => {
  594. :set_filter => 1,
  595. :group_by => 'tracker',
  596. :sort => 'id:desc'
  597. }
  598. )
  599. assert_response :success
  600. assert_equal ["Bug", "Feature request", "Support request"],
  601. css_select("tr.issue td.tracker").map(&:text).uniq
  602. end
  603. def test_index_with_query_grouped_by_tracker_in_reverse_order
  604. 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
  605. get(
  606. :index,
  607. :params => {
  608. :set_filter => 1,
  609. :group_by => 'tracker',
  610. :c => ['tracker', 'subject'],
  611. :sort => 'id:desc,tracker:desc'
  612. }
  613. )
  614. assert_response :success
  615. assert_equal ["Bug", "Feature request", "Support request"].reverse,
  616. css_select("tr.issue td.tracker").map(&:text).uniq
  617. end
  618. def test_index_with_query_id_and_project_id_should_set_session_query
  619. get(
  620. :index,
  621. :params => {
  622. :project_id => 1,
  623. :query_id => 4
  624. }
  625. )
  626. assert_response :success
  627. assert_kind_of Hash, session[:issue_query]
  628. assert_equal 4, session[:issue_query][:id]
  629. assert_equal 1, session[:issue_query][:project_id]
  630. end
  631. def test_index_with_invalid_query_id_should_respond_404
  632. get(
  633. :index,
  634. :params => {
  635. :project_id => 1,
  636. :query_id => 999
  637. }
  638. )
  639. assert_response :not_found
  640. end
  641. def test_index_with_cross_project_query_in_session_should_show_project_issues
  642. q = IssueQuery.
  643. create!(
  644. :name => "cross_project_query", :user_id => 2,
  645. :project => nil, :column_names => ['project']
  646. )
  647. @request.session[:issue_query] = {:id => q.id, :project_id => 1}
  648. with_settings :display_subprojects_issues => '0' do
  649. get(:index, :params => {:project_id => 1})
  650. end
  651. assert_response :success
  652. assert_select 'h2', :text => q.name
  653. assert_equal ["eCookbook"], css_select("tr.issue td.project").map(&:text).uniq
  654. end
  655. def test_private_query_should_not_be_available_to_other_users
  656. q = IssueQuery.
  657. create!(
  658. :name => "private", :user => User.find(2),
  659. :visibility => IssueQuery::VISIBILITY_PRIVATE,
  660. :project => nil
  661. )
  662. @request.session[:user_id] = 3
  663. get(:index, :params => {:query_id => q.id})
  664. assert_response :forbidden
  665. end
  666. def test_private_query_should_be_available_to_its_user
  667. q = IssueQuery.
  668. create!(
  669. :name => "private", :user => User.find(2),
  670. :visibility => IssueQuery::VISIBILITY_PRIVATE,
  671. :project => nil
  672. )
  673. @request.session[:user_id] = 2
  674. get(:index, :params => {:query_id => q.id})
  675. assert_response :success
  676. end
  677. def test_public_query_should_be_available_to_other_users
  678. q = IssueQuery.
  679. create!(
  680. :name => "public", :user => User.find(2),
  681. :visibility => IssueQuery::VISIBILITY_PUBLIC,
  682. :project => nil
  683. )
  684. @request.session[:user_id] = 3
  685. get(:index, :params => {:query_id => q.id})
  686. assert_response :success
  687. end
  688. def test_index_should_omit_page_param_in_export_links
  689. get(:index, :params => {:page => 2})
  690. assert_response :success
  691. assert_select 'a.atom[href="/issues.atom"]'
  692. assert_select 'a.csv[href="/issues.csv"]'
  693. assert_select 'a.pdf[href="/issues.pdf"]'
  694. assert_select 'form#csv-export-form[action="/issues.csv"]'
  695. end
  696. def test_index_should_not_warn_when_not_exceeding_export_limit
  697. with_settings :issues_export_limit => 200 do
  698. get :index
  699. assert_select '#csv-export-options p.icon-warning', 0
  700. end
  701. end
  702. def test_index_should_warn_when_exceeding_export_limit
  703. with_settings :issues_export_limit => 2 do
  704. get :index
  705. assert_select '#csv-export-options p.icon-warning', :text => %r{limit: 2}
  706. end
  707. end
  708. def test_index_should_include_query_params_as_hidden_fields_in_csv_export_form
  709. get(
  710. :index,
  711. :params => {
  712. :project_id => 1,
  713. :set_filter => "1",
  714. :tracker_id => "2",
  715. :sort => 'status',
  716. :c => ["status", "priority"]
  717. }
  718. )
  719. assert_select '#csv-export-form[action=?]', '/projects/ecookbook/issues.csv'
  720. assert_select '#csv-export-form[method=?]', 'get'
  721. assert_select '#csv-export-form' do
  722. assert_select 'input[name=?][value=?]', 'set_filter', '1'
  723. assert_select 'input[name=?][value=?]', 'f[]', 'tracker_id'
  724. assert_select 'input[name=?][value=?]', 'op[tracker_id]', '='
  725. assert_select 'input[name=?][value=?]', 'v[tracker_id][]', '2'
  726. assert_select 'input[name=?][value=?]', 'c[]', 'status'
  727. assert_select 'input[name=?][value=?]', 'c[]', 'priority'
  728. assert_select 'input[name=?][value=?]', 'sort', 'status'
  729. end
  730. get(
  731. :index,
  732. :params => {
  733. :project_id => 1,
  734. :set_filter => "1",
  735. :f => ['']
  736. }
  737. )
  738. assert_select '#csv-export-form input[name=?][value=?]', 'f[]', ''
  739. end
  740. def test_index_should_show_block_columns_in_csv_export_form
  741. field = IssueCustomField.
  742. create!(
  743. :name => 'Long text', :field_format => 'text',
  744. :full_width_layout => '1',
  745. :tracker_ids => [1], :is_for_all => true
  746. )
  747. get :index
  748. assert_response :success
  749. assert_select '#csv-export-form' do
  750. assert_select 'input[value=?]', 'description'
  751. assert_select 'input[value=?]', 'last_notes'
  752. assert_select 'input[value=?]', "cf_#{field.id}"
  753. end
  754. end
  755. def test_index_csv
  756. get(:index, :params => {:format => 'csv'})
  757. assert_response :success
  758. assert_equal 'text/csv; header=present', @response.media_type
  759. assert response.body.starts_with?("#,")
  760. lines = response.body.chomp.split("\n")
  761. # default columns + id and project
  762. assert_equal Setting.issue_list_default_columns.size + 2, lines[0].split(',').size
  763. end
  764. def test_index_csv_filename_without_query_name_param
  765. get :index, :params => {:format => 'csv'}
  766. assert_response :success
  767. assert_match /issues.csv/, @response.headers['Content-Disposition']
  768. end
  769. def test_index_csv_filename_with_query_name_param
  770. get :index, :params => {:query_name => 'My Query Name', :format => 'csv'}
  771. assert_response :success
  772. assert_match /my_query_name\.csv/, @response.headers['Content-Disposition']
  773. end
  774. def test_index_csv_with_project
  775. get(
  776. :index,
  777. :params => {
  778. :project_id => 1,
  779. :format => 'csv'
  780. }
  781. )
  782. assert_response :success
  783. assert_equal 'text/csv; header=present', @response.media_type
  784. end
  785. def test_index_csv_without_any_filters
  786. @request.session[:user_id] = 1
  787. Issue.
  788. create!(
  789. :project_id => 1, :tracker_id => 1,
  790. :status_id => 5, :subject => 'Closed issue', :author_id => 1
  791. )
  792. get(
  793. :index,
  794. :params => {
  795. :set_filter => 1,
  796. :f => [''],
  797. :format => 'csv'
  798. }
  799. )
  800. assert_response :success
  801. # -1 for headers
  802. assert_equal Issue.count, response.body.chomp.split("\n").size - 1
  803. end
  804. def test_index_csv_with_description
  805. Issue.generate!(:description => 'test_index_csv_with_description')
  806. with_settings :default_language => 'en' do
  807. get(
  808. :index,
  809. :params => {
  810. :format => 'csv',
  811. :c => [:tracker, :description]
  812. }
  813. )
  814. assert_response :success
  815. end
  816. assert_equal 'text/csv; header=present', response.media_type
  817. headers = response.body.chomp.split("\n").first.split(',')
  818. assert_include 'Description', headers
  819. assert_include 'test_index_csv_with_description', response.body
  820. end
  821. def test_index_csv_with_spent_time_column
  822. issue = Issue.
  823. create!(
  824. :project_id => 1, :tracker_id => 1,
  825. :subject => 'test_index_csv_with_spent_time_column',
  826. :author_id => 2
  827. )
  828. TimeEntry.
  829. create!(
  830. :project => issue.project, :issue => issue,
  831. :hours => 7.33, :user => User.find(2),
  832. :spent_on => Date.today
  833. )
  834. get(
  835. :index,
  836. :params => {
  837. :format => 'csv',
  838. :set_filter => '1',
  839. :c => %w(subject spent_hours)
  840. }
  841. )
  842. assert_response :success
  843. assert_equal 'text/csv; header=present', @response.media_type
  844. lines = @response.body.chomp.split("\n")
  845. assert_include "#{issue.id},#{issue.subject},7.33", lines
  846. end
  847. def test_index_csv_with_all_columns
  848. get(
  849. :index,
  850. :params => {
  851. :format => 'csv',
  852. :c => ['all_inline']
  853. }
  854. )
  855. assert_response :success
  856. assert_equal 'text/csv; header=present', @response.media_type
  857. assert_match /\A#,/, response.body
  858. lines = response.body.chomp.split("\n")
  859. assert_equal IssueQuery.new.available_inline_columns.size, lines[0].split(',').size
  860. end
  861. def test_index_csv_with_multi_column_field
  862. CustomField.find(1).update_attribute :multiple, true
  863. issue = Issue.find(1)
  864. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  865. issue.save!
  866. get(
  867. :index,
  868. :params => {
  869. :format => 'csv',
  870. :c => ['tracker', "cf_1"]
  871. }
  872. )
  873. assert_response :success
  874. lines = @response.body.chomp.split("\n")
  875. assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
  876. end
  877. def test_index_csv_should_format_float_custom_fields_with_csv_decimal_separator
  878. field =
  879. IssueCustomField.
  880. create!(
  881. :name => 'Float',
  882. :is_for_all => true,
  883. :tracker_ids => [1],
  884. :field_format => 'float'
  885. )
  886. issue =
  887. Issue.
  888. generate!(
  889. :project_id => 1, :tracker_id => 1,
  890. :custom_field_values => {field.id => '185.6'}
  891. )
  892. with_settings :default_language => 'fr' do
  893. get(
  894. :index,
  895. :params => {
  896. :format => 'csv',
  897. :c => ['id', 'tracker', "cf_#{field.id}"]
  898. }
  899. )
  900. assert_response :success
  901. issue_line =
  902. response.body.chomp.split("\n").
  903. map {|line| line.split(';')}.
  904. detect {|line| line[0]==issue.id.to_s}
  905. assert_include '185,60', issue_line
  906. end
  907. with_settings :default_language => 'en' do
  908. get(
  909. :index,
  910. :params => {
  911. :format => 'csv',
  912. :c => ['id', 'tracker', "cf_#{field.id}"]
  913. }
  914. )
  915. assert_response :success
  916. issue_line = response.body.chomp.
  917. split("\n").map {|line| line.split(',')}.
  918. detect {|line| line[0]==issue.id.to_s}
  919. assert_include '185.60', issue_line
  920. end
  921. end
  922. def test_index_csv_should_fill_parent_column_with_parent_id
  923. Issue.delete_all
  924. parent = Issue.generate!
  925. child = Issue.generate!(:parent_issue_id => parent.id)
  926. with_settings :default_language => 'en' do
  927. get(
  928. :index,
  929. :params => {
  930. :format => 'csv',
  931. :c => %w(parent)
  932. }
  933. )
  934. end
  935. lines = response.body.split("\n")
  936. assert_include "#{child.id},#{parent.id}", lines
  937. end
  938. def test_index_csv_big_5
  939. with_settings :default_language => "zh-TW" do
  940. str_utf8 = '一月'
  941. str_big5 = (+"\xa4@\xa4\xeb").force_encoding('Big5')
  942. issue = Issue.generate!(:subject => str_utf8)
  943. get(
  944. :index, :params => {
  945. :project_id => 1,
  946. :subject => str_utf8,
  947. :format => 'csv'
  948. }
  949. )
  950. assert_equal 'text/csv; header=present', @response.media_type
  951. lines = @response.body.chomp.split("\n")
  952. header = lines[0]
  953. status = (+"\xaa\xac\xbaA").force_encoding('Big5')
  954. assert_include status, header
  955. issue_line = lines.find {|l| l =~ /^#{issue.id},/}
  956. assert_include str_big5, issue_line
  957. end
  958. end
  959. def test_index_csv_cannot_convert_should_be_replaced_big_5
  960. with_settings :default_language => "zh-TW" do
  961. str_utf8 = '以内'
  962. issue = Issue.generate!(:subject => str_utf8)
  963. get(
  964. :index, :params => {
  965. :project_id => 1,
  966. :subject => str_utf8,
  967. :c => ['status', 'subject'],
  968. :format => 'csv',
  969. :set_filter => 1
  970. }
  971. )
  972. assert_equal 'text/csv; header=present', @response.media_type
  973. lines = @response.body.chomp.split("\n")
  974. header = lines[0]
  975. issue_line = lines.find {|l| l =~ /^#{issue.id},/}
  976. s1 = (+"\xaa\xac\xbaA").force_encoding('Big5') # status
  977. assert header.include?(s1)
  978. s2 = issue_line.split(",")[2]
  979. s3 = (+"\xa5H?").force_encoding('Big5') # subject
  980. assert_equal s3, s2
  981. end
  982. end
  983. def test_index_csv_tw
  984. with_settings :default_language => "zh-TW" do
  985. str1 = "test_index_csv_tw"
  986. issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
  987. get(
  988. :index,
  989. :params => {
  990. :project_id => 1,
  991. :subject => str1,
  992. :c => ['estimated_hours', 'subject'],
  993. :format => 'csv',
  994. :set_filter => 1
  995. }
  996. )
  997. assert_equal 'text/csv; header=present', @response.media_type
  998. lines = @response.body.chomp.split("\n")
  999. assert_include "#{issue.id},1234.50,#{str1}", lines
  1000. end
  1001. end
  1002. def test_index_csv_fr
  1003. with_settings :default_language => "fr" do
  1004. str1 = "test_index_csv_fr"
  1005. issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
  1006. get(
  1007. :index,
  1008. :params => {
  1009. :project_id => 1,
  1010. :subject => str1,
  1011. :c => ['estimated_hours', 'subject'],
  1012. :format => 'csv',
  1013. :set_filter => 1
  1014. }
  1015. )
  1016. assert_equal 'text/csv; header=present', @response.media_type
  1017. lines = @response.body.chomp.split("\n")
  1018. assert_include "#{issue.id};1234,50;#{str1}", lines
  1019. end
  1020. end
  1021. def test_index_csv_should_not_change_selected_columns
  1022. get(
  1023. :index,
  1024. :params => {
  1025. :set_filter => 1,
  1026. :c => ["subject", "due_date"],
  1027. :project_id => "ecookbook"
  1028. }
  1029. )
  1030. assert_response :success
  1031. assert_equal [:subject, :due_date], session[:issue_query][:column_names]
  1032. get(
  1033. :index,
  1034. :params => {
  1035. :set_filter => 1,
  1036. :c =>["all_inline"],
  1037. :project_id => "ecookbook",
  1038. :format => 'csv'
  1039. }
  1040. )
  1041. assert_response :success
  1042. assert_equal [:subject, :due_date], session[:issue_query][:column_names]
  1043. end
  1044. def test_index_pdf
  1045. ["en", "zh", "zh-TW", "ja", "ko", "ar"].each do |lang|
  1046. with_settings :default_language => lang do
  1047. get :index
  1048. assert_response :success
  1049. get(:index, :params => {:format => 'pdf'})
  1050. assert_response :success
  1051. assert_equal 'application/pdf', @response.media_type
  1052. get(
  1053. :index,
  1054. :params => {
  1055. :project_id => 1,
  1056. :format => 'pdf'
  1057. }
  1058. )
  1059. assert_response :success
  1060. assert_equal 'application/pdf', @response.media_type
  1061. get(
  1062. :index,
  1063. :params => {
  1064. :project_id => 1,
  1065. :query_id => 6,
  1066. :format => 'pdf'
  1067. }
  1068. )
  1069. assert_response :success
  1070. assert_equal 'application/pdf', @response.media_type
  1071. end
  1072. end
  1073. end
  1074. def test_index_pdf_with_query_grouped_by_list_custom_field
  1075. get(
  1076. :index,
  1077. :params => {
  1078. :project_id => 1,
  1079. :query_id => 9,
  1080. :format => 'pdf'
  1081. }
  1082. )
  1083. assert_response :success
  1084. assert_equal 'application/pdf', @response.media_type
  1085. end
  1086. def test_index_pdf_with_query_grouped_by_full_width_text_custom_field
  1087. field = IssueCustomField.
  1088. create!(
  1089. :name => 'Long text', :field_format => 'text',
  1090. :full_width_layout => '1',
  1091. :tracker_ids => [1, 3], :is_for_all => true
  1092. )
  1093. issue = Issue.find(1)
  1094. issue.custom_field_values = {field.id => 'This is a long text'}
  1095. issue.save!
  1096. get(
  1097. :index,
  1098. :params => {
  1099. :set_filter => 1,
  1100. :c => ['subject', 'description', "cf_#{field.id}"],
  1101. :format => 'pdf'
  1102. }
  1103. )
  1104. assert_response :success
  1105. assert_equal 'application/pdf', @response.media_type
  1106. end
  1107. def test_index_pdf_filename_without_query
  1108. get :index, :params => {:format => 'pdf'}
  1109. assert_response :success
  1110. assert_match /issues.pdf/, @response.headers['Content-Disposition']
  1111. end
  1112. def test_index_pdf_filename_with_query
  1113. query = IssueQuery.create!(:name => 'My Query Name', :visibility => IssueQuery::VISIBILITY_PUBLIC)
  1114. get :index, :params => {:query_id => query.id, :format => 'pdf'}
  1115. assert_response :success
  1116. assert_match /my_query_name\.pdf/, @response.headers['Content-Disposition']
  1117. end
  1118. def test_index_atom
  1119. get(
  1120. :index,
  1121. :params => {
  1122. :project_id => 'ecookbook',
  1123. :format => 'atom'
  1124. }
  1125. )
  1126. assert_response :success
  1127. assert_equal 'application/atom+xml', response.media_type
  1128. assert_select 'feed' do
  1129. assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
  1130. assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
  1131. assert_select 'entry link[href=?]', 'http://test.host/issues/1'
  1132. end
  1133. end
  1134. def test_index_should_include_back_url_input
  1135. get(
  1136. :index,
  1137. :params => {
  1138. :project_id => 'ecookbook',
  1139. :foo => 'bar'
  1140. }
  1141. )
  1142. assert_response :success
  1143. assert_select 'input[name=back_url][value=?]', '/projects/ecookbook/issues?foo=bar'
  1144. end
  1145. def test_index_sort
  1146. get(:index, :params => {:sort => 'tracker,id:desc'})
  1147. assert_response :success
  1148. assert_equal(
  1149. issues_in_list.sort_by {|issue| [issue.tracker.position, -issue.id]},
  1150. issues_in_list
  1151. )
  1152. assert_select 'table.issues.sort-by-tracker.sort-asc'
  1153. end
  1154. def test_index_sort_by_field_not_included_in_columns
  1155. with_settings :issue_list_default_columns => %w(subject author) do
  1156. get(:index, :params => {:sort => 'tracker'})
  1157. assert_response :success
  1158. end
  1159. end
  1160. def test_index_sort_by_assigned_to
  1161. get(:index, :params => {:sort => 'assigned_to'})
  1162. assert_response :success
  1163. assignees = issues_in_list.filter_map(&:assigned_to)
  1164. assert_equal assignees.sort, assignees
  1165. assert_select 'table.issues.sort-by-assigned-to.sort-asc'
  1166. end
  1167. def test_index_sort_by_assigned_to_desc
  1168. get(:index, :params => {:sort => 'assigned_to:desc'})
  1169. assert_response :success
  1170. assignees = issues_in_list.filter_map(&:assigned_to)
  1171. assert_equal assignees.sort.reverse, assignees
  1172. assert_select 'table.issues.sort-by-assigned-to.sort-desc'
  1173. end
  1174. def test_index_group_by_assigned_to
  1175. get(
  1176. :index,
  1177. :params => {
  1178. :group_by => 'assigned_to',
  1179. :sort => 'priority'
  1180. }
  1181. )
  1182. assert_response :success
  1183. end
  1184. def test_index_sort_by_author
  1185. get(
  1186. :index,
  1187. :params => {
  1188. :sort => 'author',
  1189. :c => ['author']
  1190. }
  1191. )
  1192. assert_response :success
  1193. authors = issues_in_list.map(&:author)
  1194. assert_equal authors.sort, authors
  1195. end
  1196. def test_index_sort_by_author_desc
  1197. get(:index, :params => {:sort => 'author:desc'})
  1198. assert_response :success
  1199. authors = issues_in_list.map(&:author)
  1200. assert_equal authors.sort.reverse, authors
  1201. end
  1202. def test_index_group_by_author
  1203. get(
  1204. :index,
  1205. :params => {
  1206. :group_by => 'author',
  1207. :sort => 'priority'
  1208. }
  1209. )
  1210. assert_response :success
  1211. end
  1212. def test_index_sort_by_last_updated_by
  1213. get(:index, :params => {:sort => 'last_updated_by'})
  1214. assert_response :success
  1215. assert_select 'table.issues.sort-by-last-updated-by.sort-asc'
  1216. end
  1217. def test_index_sort_by_last_updated_by_desc
  1218. get(:index, :params => {:sort => 'last_updated_by:desc'})
  1219. assert_response :success
  1220. assert_select 'table.issues.sort-by-last-updated-by.sort-desc'
  1221. end
  1222. def test_index_sort_by_spent_hours
  1223. get(:index, :params => {:sort => 'spent_hours:desc'})
  1224. assert_response :success
  1225. hours = issues_in_list.map(&:spent_hours)
  1226. assert_equal hours.sort.reverse, hours
  1227. end
  1228. def test_index_sort_by_spent_hours_should_sort_by_visible_spent_hours
  1229. TimeEntry.delete_all
  1230. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3)
  1231. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4)
  1232. get(
  1233. :index,
  1234. :params => {
  1235. :sort => "spent_hours:desc",
  1236. :c => ['subject', 'spent_hours']
  1237. }
  1238. )
  1239. assert_response :success
  1240. assert_equal ['4:00', '3:00', '0:00'], columns_values_in_list('spent_hours').first(3)
  1241. Project.find(3).disable_module!(:time_tracking)
  1242. get(
  1243. :index,
  1244. :params => {
  1245. :sort => "spent_hours:desc",
  1246. :c => ['subject', 'spent_hours']
  1247. }
  1248. )
  1249. assert_response :success
  1250. assert_equal ['3:00', '0:00', '0:00'], columns_values_in_list('spent_hours').first(3)
  1251. end
  1252. def test_index_sort_by_total_spent_hours
  1253. get(:index, :params => {:sort => 'total_spent_hours:desc'})
  1254. assert_response :success
  1255. hours = issues_in_list.map(&:total_spent_hours)
  1256. assert_equal hours.sort.reverse, hours
  1257. end
  1258. def test_index_sort_by_total_estimated_hours
  1259. get(:index, :params => {:sort => 'total_estimated_hours:desc'})
  1260. assert_response :success
  1261. hours = issues_in_list.map(&:total_estimated_hours)
  1262. # Removes nil because the position of NULL is database dependent
  1263. hours.compact!
  1264. assert_equal hours.sort.reverse, hours
  1265. end
  1266. def test_index_sort_by_user_custom_field
  1267. cf = IssueCustomField.
  1268. create!(
  1269. :name => 'User',
  1270. :is_for_all => true,
  1271. :tracker_ids => [1, 2, 3],
  1272. :field_format => 'user'
  1273. )
  1274. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
  1275. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
  1276. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
  1277. CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
  1278. get(
  1279. :index,
  1280. :params => {
  1281. :project_id => 1,
  1282. :set_filter => 1,
  1283. :sort => "cf_#{cf.id},id"
  1284. }
  1285. )
  1286. assert_response :success
  1287. assert_equal(
  1288. [2, 3, 1],
  1289. issues_in_list.select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
  1290. )
  1291. end
  1292. def test_index_with_columns
  1293. columns = ['tracker', 'subject', 'assigned_to', 'buttons']
  1294. get(
  1295. :index,
  1296. :params => {
  1297. :set_filter => 1,
  1298. :c => columns
  1299. }
  1300. )
  1301. assert_response :success
  1302. # query should use specified columns + id and checkbox
  1303. assert_select 'table.issues thead' do
  1304. assert_select 'th', columns.size + 2
  1305. assert_select 'th.tracker'
  1306. assert_select 'th.subject'
  1307. assert_select 'th.assigned_to'
  1308. assert_select 'th.buttons'
  1309. end
  1310. # columns should be stored in session
  1311. assert_kind_of Hash, session[:issue_query]
  1312. assert_kind_of Array, session[:issue_query][:column_names]
  1313. assert_equal columns, session[:issue_query][:column_names].map(&:to_s)
  1314. # ensure only these columns are kept in the selected columns list
  1315. assert_select 'select[name=?] option', 'c[]' do
  1316. assert_select 'option', 3
  1317. assert_select 'option[value=tracker]'
  1318. assert_select 'option[value=project]', 0
  1319. end
  1320. end
  1321. def test_index_without_project_should_implicitly_add_project_column_to_default_columns
  1322. with_settings :issue_list_default_columns => ['tracker', 'subject', 'assigned_to'] do
  1323. get(:index, :params => {:set_filter => 1})
  1324. end
  1325. # query should use specified columns
  1326. assert_equal ["#", "Project", "Tracker", "Subject", "Assignee"], columns_in_issues_list
  1327. end
  1328. def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
  1329. with_settings :issue_list_default_columns => ['tracker', 'subject', 'assigned_to'] do
  1330. columns = ['id', 'tracker', 'subject', 'assigned_to']
  1331. get(
  1332. :index,
  1333. :params => {
  1334. :set_filter => 1,
  1335. :c => columns
  1336. }
  1337. )
  1338. end
  1339. # query should use specified columns
  1340. assert_equal ["#", "Tracker", "Subject", "Assignee"], columns_in_issues_list
  1341. end
  1342. def test_index_with_default_columns_should_respect_default_columns_order
  1343. columns = ['assigned_to', 'subject', 'status', 'tracker']
  1344. with_settings :issue_list_default_columns => columns do
  1345. get(
  1346. :index,
  1347. :params => {
  1348. :project_id => 1,
  1349. :set_filter => 1
  1350. }
  1351. )
  1352. assert_equal ["#", "Assignee", "Subject", "Status", "Tracker"], columns_in_issues_list
  1353. end
  1354. end
  1355. def test_index_with_custom_field_column
  1356. columns = %w(tracker subject cf_2)
  1357. get(
  1358. :index,
  1359. :params => {
  1360. :set_filter => 1,
  1361. :c => columns
  1362. }
  1363. )
  1364. assert_response :success
  1365. # query should use specified columns
  1366. assert_equal ["#", "Tracker", "Subject", "Searchable field"], columns_in_issues_list
  1367. assert_select 'table.issues' do
  1368. assert_select 'th.cf_2.string'
  1369. assert_select 'td.cf_2.string'
  1370. end
  1371. end
  1372. def test_index_with_multi_custom_field_column
  1373. field = CustomField.find(1)
  1374. field.update_attribute :multiple, true
  1375. issue = Issue.find(1)
  1376. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  1377. issue.save!
  1378. get(
  1379. :index,
  1380. :params => {
  1381. :set_filter => 1,
  1382. :c => %w(tracker subject cf_1)
  1383. }
  1384. )
  1385. assert_response :success
  1386. assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
  1387. end
  1388. def test_index_with_multi_user_custom_field_column
  1389. field =
  1390. IssueCustomField.
  1391. create!(
  1392. :name => 'Multi user', :field_format => 'user',
  1393. :multiple => true,
  1394. :tracker_ids => [1], :is_for_all => true
  1395. )
  1396. issue = Issue.find(1)
  1397. issue.custom_field_values = {field.id => ['2', '3']}
  1398. issue.save!
  1399. get(
  1400. :index,
  1401. :params => {
  1402. :set_filter => 1,
  1403. :c => ['tracker', 'subject', "cf_#{field.id}"]
  1404. }
  1405. )
  1406. assert_response :success
  1407. assert_select "table.issues td.cf_#{field.id}" do
  1408. assert_select 'a', 2
  1409. assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
  1410. assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
  1411. end
  1412. end
  1413. def test_index_with_date_column
  1414. with_settings :date_format => '%d/%m/%Y' do
  1415. Issue.find(1).update_attribute :start_date, '1987-08-24'
  1416. get(
  1417. :index,
  1418. :params => {
  1419. :set_filter => 1,
  1420. :c => %w(start_date)
  1421. }
  1422. )
  1423. assert_select 'table.issues' do
  1424. assert_select 'th.start_date'
  1425. assert_select 'td.start_date', :text => '24/08/1987'
  1426. end
  1427. end
  1428. end
  1429. def test_index_with_done_ratio_column
  1430. Issue.find(1).update_attribute :done_ratio, 40
  1431. get(
  1432. :index,
  1433. :params => {
  1434. :set_filter => 1,
  1435. :c => %w(done_ratio)
  1436. }
  1437. )
  1438. assert_select 'table.issues td.done_ratio' do
  1439. assert_select 'table.progress' do
  1440. assert_select 'td.closed[style=?]', 'width: 40%;'
  1441. end
  1442. end
  1443. end
  1444. def test_index_with_spent_hours_column
  1445. Issue.expects(:load_visible_spent_hours).once
  1446. get(
  1447. :index,
  1448. :params => {
  1449. :set_filter => 1,
  1450. :c => %w(subject spent_hours)
  1451. }
  1452. )
  1453. assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1:00'
  1454. end
  1455. def test_index_with_total_spent_hours_column
  1456. Issue.expects(:load_visible_total_spent_hours).once
  1457. get(
  1458. :index,
  1459. :params => {
  1460. :set_filter => 1,
  1461. :c => %w(subject total_spent_hours)
  1462. }
  1463. )
  1464. assert_select 'table.issues tr#issue-3 td.total_spent_hours', :text => '1:00'
  1465. end
  1466. def test_index_with_total_estimated_hours_column
  1467. get(
  1468. :index,
  1469. :params => {
  1470. :set_filter => 1,
  1471. :c => %w(subject total_estimated_hours)
  1472. }
  1473. )
  1474. assert_select 'table.issues td.total_estimated_hours'
  1475. end
  1476. def test_index_should_not_show_spent_hours_column_without_permission
  1477. Role.anonymous.remove_permission! :view_time_entries
  1478. get(
  1479. :index,
  1480. :params => {
  1481. :set_filter => 1,
  1482. :c => %w(subject spent_hours)
  1483. }
  1484. )
  1485. assert_select 'td.spent_hours', 0
  1486. end
  1487. def test_index_with_fixed_version_column
  1488. get(
  1489. :index,
  1490. :params => {
  1491. :set_filter => 1,
  1492. :c => %w(fixed_version)
  1493. }
  1494. )
  1495. assert_select 'table.issues td.fixed_version' do
  1496. assert_select 'a[href=?]', '/versions/2', :text => 'eCookbook - 1.0'
  1497. end
  1498. end
  1499. def test_index_with_relations_column
  1500. IssueRelation.delete_all
  1501. IssueRelation.
  1502. create!(
  1503. :relation_type => "relates",
  1504. :issue_from => Issue.find(1), :issue_to => Issue.find(7)
  1505. )
  1506. IssueRelation.
  1507. create!(
  1508. :relation_type => "relates",
  1509. :issue_from => Issue.find(8), :issue_to => Issue.find(1)
  1510. )
  1511. IssueRelation.
  1512. create!(
  1513. :relation_type => "blocks",
  1514. :issue_from => Issue.find(1), :issue_to => Issue.find(11)
  1515. )
  1516. IssueRelation.
  1517. create!(
  1518. :relation_type => "blocks", :issue_from => Issue.find(12),
  1519. :issue_to => Issue.find(2)
  1520. )
  1521. get(
  1522. :index,
  1523. :params => {
  1524. :set_filter => 1,
  1525. :c => %w(subject relations)
  1526. }
  1527. )
  1528. assert_response :success
  1529. assert_select "tr#issue-1 td.relations" do
  1530. assert_select "span", 3
  1531. assert_select "span", :text => "Related to #7"
  1532. assert_select "span", :text => "Related to #8"
  1533. assert_select "span", :text => "Blocks #11"
  1534. end
  1535. assert_select "tr#issue-2 td.relations" do
  1536. assert_select "span", 1
  1537. assert_select "span", :text => "Blocked by #12"
  1538. end
  1539. assert_select "tr#issue-3 td.relations" do
  1540. assert_select "span", 0
  1541. end
  1542. get(
  1543. :index,
  1544. :params => {
  1545. :set_filter => 1,
  1546. :c => %w(relations),
  1547. :format => 'csv'
  1548. }
  1549. )
  1550. assert_response :success
  1551. assert_equal 'text/csv; header=present', response.media_type
  1552. lines = response.body.chomp.split("\n")
  1553. assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
  1554. assert_include '2,Blocked by #12', lines
  1555. assert_include '3,""', lines
  1556. get(
  1557. :index,
  1558. :params => {
  1559. :set_filter => 1,
  1560. :c => %w(subject relations),
  1561. :format => 'pdf'
  1562. }
  1563. )
  1564. assert_response :success
  1565. assert_equal 'application/pdf', response.media_type
  1566. end
  1567. def test_index_with_description_column
  1568. get(
  1569. :index,
  1570. :params => {
  1571. :set_filter => 1,
  1572. :c => %w(subject description)
  1573. }
  1574. )
  1575. assert_select 'table.issues thead th', 4 # columns: chekbox + id + subject
  1576. assert_select 'td.description[colspan="4"]', :text => 'Unable to print recipes'
  1577. get(
  1578. :index,
  1579. :params => {
  1580. :set_filter => 1,
  1581. :c => %w(subject description),
  1582. :format => 'pdf'
  1583. }
  1584. )
  1585. assert_response :success
  1586. assert_equal 'application/pdf', response.media_type
  1587. end
  1588. def test_index_with_last_notes_column
  1589. with_settings :text_formatting => 'textile' do
  1590. get(
  1591. :index,
  1592. :params => {
  1593. :set_filter => 1,
  1594. :c => %w(subject last_notes)
  1595. }
  1596. )
  1597. assert_response :success
  1598. assert_select 'table.issues thead th', 4 # columns: chekbox + id + subject
  1599. assert_select 'td.last_notes[colspan="4"]', :text => 'Some notes with Redmine links: #2, r2.'
  1600. assert_select(
  1601. 'td.last_notes[colspan="4"]',
  1602. :text => 'A comment with inline image: and a reference to #1 and r2.'
  1603. )
  1604. get(
  1605. :index,
  1606. :params => {
  1607. :set_filter => 1,
  1608. :c => %w(subject last_notes),
  1609. :format => 'pdf'
  1610. }
  1611. )
  1612. assert_response :success
  1613. assert_equal 'application/pdf', response.media_type
  1614. end
  1615. end
  1616. def test_index_with_last_notes_column_should_display_private_notes_with_permission_only
  1617. journal = Journal.
  1618. create!(
  1619. :journalized => Issue.find(2),
  1620. :notes => 'Public notes', :user_id => 1
  1621. )
  1622. journal = Journal.
  1623. create!(
  1624. :journalized => Issue.find(2),
  1625. :notes => 'Privates notes', :private_notes => true,
  1626. :user_id => 1
  1627. )
  1628. @request.session[:user_id] = 2
  1629. get(
  1630. :index,
  1631. :params => {
  1632. :set_filter => 1,
  1633. :c => %w(subject last_notes)
  1634. }
  1635. )
  1636. assert_response :success
  1637. assert_select 'td.last_notes[colspan="4"]', :text => 'Privates notes'
  1638. Role.find(1).remove_permission! :view_private_notes
  1639. get(
  1640. :index,
  1641. :params => {
  1642. :set_filter => 1,
  1643. :c => %w(subject last_notes)
  1644. }
  1645. )
  1646. assert_response :success
  1647. assert_select 'td.last_notes[colspan="4"]', :text => 'Public notes'
  1648. end
  1649. def test_index_with_description_and_last_notes_columns_should_display_column_name
  1650. get(
  1651. :index,
  1652. :params => {
  1653. :set_filter => 1,
  1654. :c => %w(subject last_notes description)
  1655. }
  1656. )
  1657. assert_response :success
  1658. assert_select 'td.last_notes[colspan="4"] span', :text => 'Last notes'
  1659. assert_select 'td.description[colspan="4"] span', :text => 'Description'
  1660. end
  1661. def test_index_with_full_width_layout_custom_field_column_should_show_column_as_block_column
  1662. field = IssueCustomField.
  1663. create!(
  1664. :name => 'Long text', :field_format => 'text',
  1665. :full_width_layout => '1',
  1666. :tracker_ids => [1], :is_for_all => true
  1667. )
  1668. issue = Issue.find(1)
  1669. issue.custom_field_values = {field.id => 'This is a long text'}
  1670. issue.save!
  1671. get(
  1672. :index,
  1673. :params => {
  1674. :set_filter => 1,
  1675. :c => ['subject', 'description', "cf_#{field.id}"]
  1676. }
  1677. )
  1678. assert_response :success
  1679. assert_select 'td.description[colspan="4"] span', :text => 'Description'
  1680. assert_select "td.cf_#{field.id} span", :text => 'Long text'
  1681. end
  1682. def test_index_with_parent_column
  1683. Issue.delete_all
  1684. parent = Issue.generate!
  1685. child = Issue.generate!(:parent_issue_id => parent.id)
  1686. get(:index, :params => {:c => %w(parent)})
  1687. assert_select 'td.parent', :text => "#{parent.tracker} ##{parent.id}"
  1688. assert_select 'td.parent a[title=?]', parent.subject
  1689. end
  1690. def test_index_with_parent_subject_column
  1691. Issue.delete_all
  1692. parent = Issue.generate!
  1693. child = Issue.generate!(:parent_issue_id => parent.id)
  1694. get(:index, :params => {:c => %w(parent.subject)})
  1695. assert_select 'table.issues' do
  1696. assert_select 'th.parent-subject', :text => l(:field_parent_issue_subject)
  1697. assert_select "tr#issue-#{child.id}" do
  1698. assert_select 'td.parent-subject', :text => parent.subject
  1699. end
  1700. end
  1701. end
  1702. def test_index_with_last_updated_by_column
  1703. get(
  1704. :index, :params => {
  1705. :c => %w(subject last_updated_by),
  1706. :issue_id => '1,2,3',
  1707. :sort => 'id',
  1708. :set_filter => '1'
  1709. }
  1710. )
  1711. assert_select 'td.last_updated_by'
  1712. assert_equal ["John Smith", "John Smith", ""], css_select('td.last_updated_by').map(&:text)
  1713. end
  1714. def test_index_with_attachments_column
  1715. get(
  1716. :index,
  1717. :params => {
  1718. :c => %w(subject attachments),
  1719. :set_filter => '1',
  1720. :sort => 'id'
  1721. }
  1722. )
  1723. assert_response :success
  1724. assert_select 'td.attachments'
  1725. assert_select 'tr#issue-2' do
  1726. assert_select 'td.attachments' do
  1727. assert_select 'span:nth-of-type(1)' do
  1728. assert_select 'a[href=?]', '/attachments/4', :text => 'source.rb'
  1729. assert_select 'a[href=?].icon-download', '/attachments/download/4/source.rb'
  1730. end
  1731. assert_select 'span:nth-of-type(2)' do
  1732. assert_select 'a[href=?]', '/attachments/10', :text => 'picture.jpg'
  1733. assert_select 'a[href=?].icon-download', '/attachments/download/10/picture.jpg'
  1734. end
  1735. end
  1736. end
  1737. end
  1738. def test_index_with_attachments_column_as_csv
  1739. get(
  1740. :index,
  1741. :params => {
  1742. :c => %w(subject attachments),
  1743. :set_filter => '1',
  1744. :sort => 'id',
  1745. :format => 'csv'
  1746. }
  1747. )
  1748. assert_response :success
  1749. assert_include "\"source.rb\npicture.jpg\"", response.body
  1750. end
  1751. def test_index_with_watchers_column
  1752. @request.session[:user_id] = 2
  1753. get(
  1754. :index,
  1755. :params => {
  1756. :c => %w(subject watcher_users),
  1757. :set_filter => '1',
  1758. :sort => 'id',
  1759. }
  1760. )
  1761. assert_response :success
  1762. assert_select 'td.watcher_users'
  1763. assert_select 'tr#issue-2' do
  1764. assert_select 'td.watcher_users' do
  1765. assert_select 'a[href=?]', '/users/1', :text => User.find(1).name
  1766. assert_select 'a[href=?]', '/users/3', :text => User.find(3).name
  1767. end
  1768. end
  1769. end
  1770. def test_index_with_watchers_column_only_visible_watchers
  1771. @request.session[:user_id] = 3
  1772. User.find(3).roles.first.remove_permission! :view_issue_watchers
  1773. get(
  1774. :index,
  1775. :params => {
  1776. :c => %w(subject watcher_users),
  1777. :set_filter => '1',
  1778. :sort => 'id',
  1779. }
  1780. )
  1781. assert_response :success
  1782. assert_select 'td.watcher_users'
  1783. assert_select 'tr#issue-2' do
  1784. assert_select 'td.watcher_users' do
  1785. assert_select 'a[href=?]', '/users/1', 0
  1786. # Currently not implemented, see https://www.redmine.org/issues/29894#note-17
  1787. # You can only know that you are a watcher yourself
  1788. # assert_select 'a[href=?]', '/users/3', :text => User.find(3).name
  1789. end
  1790. end
  1791. end
  1792. def test_index_with_watchers_column_as_csv
  1793. @request.session[:user_id] = 2
  1794. get(
  1795. :index,
  1796. :params => {
  1797. :c => %w(subject watcher_users),
  1798. :set_filter => '1',
  1799. :sort => 'id',
  1800. :format => 'csv',
  1801. }
  1802. )
  1803. assert_response :success
  1804. lines = CSV.parse(response.body)
  1805. # Issue with ID 2 is the second issue in the CSV
  1806. # Column 3 is watchers_users
  1807. watchers = lines[2][2].split("\n").sort
  1808. assert_equal [User.find(3).name, User.find(1).name], watchers
  1809. end
  1810. def test_index_with_estimated_hours_total
  1811. Issue.delete_all
  1812. Issue.generate!(:estimated_hours => '5:30')
  1813. Issue.generate!(:estimated_hours => '1:06')
  1814. get(:index, :params => {:t => %w(estimated_hours)})
  1815. assert_response :success
  1816. assert_select '.query-totals'
  1817. assert_select '.total-for-estimated-hours span.value', :text => '6:36'
  1818. assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]'
  1819. end
  1820. def test_index_with_grouped_query_and_estimated_hours_total
  1821. Issue.delete_all
  1822. Issue.generate!(:estimated_hours => '5:30', :category_id => 1)
  1823. Issue.generate!(:estimated_hours => '2:18', :category_id => 1)
  1824. Issue.generate!(:estimated_hours => '1:06', :category_id => 2)
  1825. Issue.generate!(:estimated_hours => '4:36')
  1826. get(
  1827. :index,
  1828. :params => {
  1829. :t => %w(estimated_hours),
  1830. :group_by => 'category'
  1831. }
  1832. )
  1833. assert_response :success
  1834. assert_select '.query-totals'
  1835. assert_select '.query-totals .total-for-estimated-hours span.value', :text => '13:30'
  1836. assert_select 'tr.group', :text => /Printing/ do
  1837. assert_select '.total-for-estimated-hours span.value', :text => '7:48'
  1838. end
  1839. assert_select 'tr.group', :text => /Recipes/ do
  1840. assert_select '.total-for-estimated-hours span.value', :text => '1:06'
  1841. end
  1842. assert_select 'tr.group', :text => /blank/ do
  1843. assert_select '.total-for-estimated-hours span.value', :text => '4:36'
  1844. end
  1845. end
  1846. def test_index_with_int_custom_field_total
  1847. field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
  1848. CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
  1849. CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
  1850. get(:index, :params => {:t => ["cf_#{field.id}"]})
  1851. assert_response :success
  1852. assert_select '.query-totals'
  1853. assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
  1854. end
  1855. def test_index_with_spent_time_total_should_sum_visible_spent_time_only
  1856. TimeEntry.delete_all
  1857. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3)
  1858. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4)
  1859. get :index, :params => {:t => ["spent_hours"]}
  1860. assert_response :success
  1861. assert_select ".total-for-spent-hours span.value", :text => '7:00'
  1862. Project.find(3).disable_module!(:time_tracking)
  1863. get :index, :params => {:t => ["spent_hours"]}
  1864. assert_response :success
  1865. assert_select ".total-for-spent-hours span.value", :text => '3:00'
  1866. end
  1867. def test_index_totals_should_default_to_settings
  1868. with_settings :issue_list_default_totals => ['estimated_hours'] do
  1869. get :index
  1870. assert_response :success
  1871. assert_select '.total-for-estimated-hours span.value'
  1872. assert_select '.query-totals>span', 1
  1873. end
  1874. end
  1875. def test_index_send_html_if_query_is_invalid
  1876. get(
  1877. :index,
  1878. :params => {
  1879. :f => ['start_date'],
  1880. :op => {
  1881. :start_date => '='
  1882. }
  1883. }
  1884. )
  1885. assert_equal 'text/html', @response.media_type
  1886. assert_select_error /Start date cannot be blank/i
  1887. end
  1888. def test_index_send_nothing_if_query_is_invalid
  1889. get(
  1890. :index,
  1891. :params => {
  1892. :f => ['start_date'],
  1893. :op => {
  1894. :start_date => '='
  1895. },
  1896. :format => 'csv'
  1897. }
  1898. )
  1899. assert_equal 'text/csv', @response.media_type
  1900. assert @response.body.blank?
  1901. end
  1902. def test_index_should_include_new_issue_link
  1903. @request.session[:user_id] = 2
  1904. get(:index, :params => {:project_id => 1})
  1905. assert_select(
  1906. '#content a.new-issue[href="/projects/ecookbook/issues/new"]',
  1907. :text => 'New issue'
  1908. )
  1909. end
  1910. def test_index_should_not_include_new_issue_link_for_project_without_trackers
  1911. Project.find(1).trackers.clear
  1912. @request.session[:user_id] = 2
  1913. get(:index, :params => {:project_id => 1})
  1914. assert_select '#content a.new-issue', 0
  1915. end
  1916. def test_index_should_not_include_new_issue_link_for_users_with_copy_issues_permission_only
  1917. role = Role.find(1)
  1918. role.remove_permission! :add_issues
  1919. role.add_permission! :copy_issues
  1920. @request.session[:user_id] = 2
  1921. get(:index, :params => {:project_id => 1})
  1922. assert_select '#content a.new-issue', 0
  1923. end
  1924. def test_index_without_project_should_include_new_issue_link
  1925. @request.session[:user_id] = 2
  1926. get :index
  1927. assert_select '#content a.new-issue[href="/issues/new"]', :text => 'New issue'
  1928. end
  1929. def test_index_should_show_setting_link_with_edit_project_permission
  1930. role = Role.find(1)
  1931. role.add_permission! :edit_project
  1932. @request.session[:user_id] = 2
  1933. get(:index, :params => {:project_id => 1})
  1934. assert_select '#content a.icon-settings[href="/projects/ecookbook/settings/issues"]', 1
  1935. end
  1936. def test_index_should_not_show_setting_link_without_edit_project_permission
  1937. role = Role.find(1)
  1938. role.remove_permission! :edit_project
  1939. @request.session[:user_id] = 2
  1940. get(:index, :params => {:project_id => 1})
  1941. assert_select '#content a.icon-settings[href="/projects/ecookbook/settings/issues"]', 0
  1942. end
  1943. def test_index_should_not_include_new_issue_tab_when_disabled
  1944. with_settings :new_item_menu_tab => '0' do
  1945. @request.session[:user_id] = 2
  1946. get(:index, :params => {:project_id => 1})
  1947. assert_select '#main-menu a.new-issue', 0
  1948. end
  1949. end
  1950. def test_index_should_include_new_issue_tab_when_enabled
  1951. with_settings :new_item_menu_tab => '1' do
  1952. @request.session[:user_id] = 2
  1953. get(:index, :params => {:project_id => 1})
  1954. assert_select(
  1955. '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]',
  1956. :text => 'New issue'
  1957. )
  1958. end
  1959. end
  1960. def test_new_should_have_new_issue_tab_as_current_menu_item
  1961. with_settings :new_item_menu_tab => '1' do
  1962. @request.session[:user_id] = 2
  1963. get(:new, :params => {:project_id => 1})
  1964. assert_select '#main-menu a.new-issue.selected'
  1965. end
  1966. end
  1967. def test_index_should_not_include_new_issue_tab_for_project_without_trackers
  1968. with_settings :new_item_menu_tab => '1' do
  1969. Project.find(1).trackers.clear
  1970. @request.session[:user_id] = 2
  1971. get(:index, :params => {:project_id => 1})
  1972. assert_select '#main-menu a.new-issue', 0
  1973. end
  1974. end
  1975. def test_index_should_not_include_new_issue_tab_for_users_with_copy_issues_permission_only
  1976. with_settings :new_item_menu_tab => '1' do
  1977. role = Role.find(1)
  1978. role.remove_permission! :add_issues
  1979. role.add_permission! :copy_issues
  1980. @request.session[:user_id] = 2
  1981. get(:index, :params => {:project_id => 1})
  1982. assert_select '#main-menu a.new-issue', 0
  1983. end
  1984. end
  1985. def test_index_should_respect_timespan_format
  1986. with_settings :timespan_format => 'minutes' do
  1987. get(
  1988. :index,
  1989. :params => {
  1990. :set_filter => 1,
  1991. :c => %w(estimated_hours total_estimated_hours spent_hours total_spent_hours)
  1992. }
  1993. )
  1994. assert_select 'table.issues tr#issue-1 td.estimated_hours', :text => '200:00'
  1995. assert_select 'table.issues tr#issue-1 td.total_estimated_hours', :text => '200:00'
  1996. assert_select 'table.issues tr#issue-1 td.spent_hours', :text => '154:15'
  1997. assert_select 'table.issues tr#issue-1 td.total_spent_hours', :text => '154:15'
  1998. end
  1999. end
  2000. def test_show_by_anonymous
  2001. get(:show, :params => {:id => 1})
  2002. assert_response :success
  2003. assert_select 'div.issue div.description', :text => /Unable to print recipes/
  2004. assert_select '#content>.contextual:first-child' do
  2005. assert_select 'a', {:count => 1, :text => 'Edit'}
  2006. assert_select 'a', {:count => 0, :text => 'Log time'}
  2007. assert_select 'a', {:count => 0, :text => 'Watch'}
  2008. assert_select 'a', {:count => 0, :text => 'Copy'}
  2009. assert_select 'div.drdn-items a', {:count => 1, :text => 'Copy link'}
  2010. assert_select 'div.drdn-items a', {:count => 0, :text => 'Delete issue'}
  2011. end
  2012. # anonymous role is allowed to add a note
  2013. assert_select 'form#issue-form' do
  2014. assert_select 'fieldset' do
  2015. assert_select 'legend', :text => 'Notes'
  2016. assert_select 'textarea[name=?]', 'issue[notes]'
  2017. end
  2018. end
  2019. assert_select 'title', :text => "Bug #1: Cannot print recipes - eCookbook - Redmine"
  2020. end
  2021. def test_show_by_manager
  2022. @request.session[:user_id] = 2
  2023. get(:show, :params => {:id => 1})
  2024. assert_select 'a', :text => /Quote/
  2025. assert_select '#content>.contextual:first-child' do
  2026. assert_select 'a', {:count => 1, :text => 'Edit'}
  2027. assert_select 'a', {:count => 1, :text => 'Log time'}
  2028. assert_select 'a', {:count => 1, :text => 'Watch'}
  2029. assert_select 'a', {:count => 1, :text => 'Copy'}
  2030. assert_select 'div.drdn-items a', {:count => 1, :text => 'Copy link'}
  2031. assert_select 'div.drdn-items a', {:count => 1, :text => 'Delete issue'}
  2032. end
  2033. assert_select 'form#issue-form' do
  2034. assert_select 'fieldset' do
  2035. assert_select 'legend', :text => 'Change properties'
  2036. assert_select 'input[name=?]', 'issue[subject]'
  2037. end
  2038. assert_select 'fieldset' do
  2039. assert_select 'legend', :text => 'Log time'
  2040. assert_select 'input[name=?]', 'time_entry[hours]'
  2041. end
  2042. assert_select 'fieldset' do
  2043. assert_select 'legend', :text => 'Notes'
  2044. assert_select 'textarea[name=?]', 'issue[notes]'
  2045. end
  2046. end
  2047. end
  2048. def test_show_should_display_update_form
  2049. @request.session[:user_id] = 2
  2050. get(:show, :params => {:id => 1})
  2051. assert_response :success
  2052. assert_select 'form#issue-form' do
  2053. assert_select 'input[name=?]', 'issue[is_private]'
  2054. assert_select 'select[name=?]', 'issue[project_id]'
  2055. assert_select 'select[name=?]', 'issue[tracker_id]'
  2056. assert_select 'input[name=?]', 'issue[subject]'
  2057. assert_select 'textarea[name=?]', 'issue[description]'
  2058. assert_select 'select[name=?]', 'issue[status_id]'
  2059. assert_select 'select[name=?]', 'issue[priority_id]'
  2060. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  2061. assert_select 'select[name=?]', 'issue[category_id]'
  2062. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  2063. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  2064. assert_select 'input[name=?]', 'issue[start_date]'
  2065. assert_select 'input[name=?]', 'issue[due_date]'
  2066. assert_select 'select[name=?]', 'issue[done_ratio]'
  2067. assert_select 'input[name=?]', 'issue[custom_field_values][2]'
  2068. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  2069. assert_select 'textarea[name=?]', 'issue[notes]'
  2070. end
  2071. end
  2072. def test_show_should_display_update_form_with_minimal_permissions
  2073. Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
  2074. WorkflowTransition.where(:role_id => 1).delete_all
  2075. @request.session[:user_id] = 2
  2076. get(:show, :params => {:id => 1})
  2077. assert_response :success
  2078. assert_select 'form#issue-form' do
  2079. assert_select 'input[name=?]', 'issue[is_private]', 0
  2080. assert_select 'select[name=?]', 'issue[project_id]', 0
  2081. assert_select 'select[name=?]', 'issue[tracker_id]', 0
  2082. assert_select 'input[name=?]', 'issue[subject]', 0
  2083. assert_select 'textarea[name=?]', 'issue[description]', 0
  2084. assert_select 'select[name=?]', 'issue[status_id]', 0
  2085. assert_select 'select[name=?]', 'issue[priority_id]', 0
  2086. assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
  2087. assert_select 'select[name=?]', 'issue[category_id]', 0
  2088. assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
  2089. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  2090. assert_select 'input[name=?]', 'issue[start_date]', 0
  2091. assert_select 'input[name=?]', 'issue[due_date]', 0
  2092. assert_select 'select[name=?]', 'issue[done_ratio]', 0
  2093. assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
  2094. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  2095. assert_select 'textarea[name=?]', 'issue[notes]'
  2096. end
  2097. end
  2098. def test_show_should_not_display_update_form_without_permissions
  2099. Role.find(1).update_attribute :permissions, [:view_issues]
  2100. @request.session[:user_id] = 2
  2101. get(:show, :params => {:id => 1})
  2102. assert_response :success
  2103. assert_select 'form#issue-form', 0
  2104. end
  2105. def test_update_form_should_not_display_inactive_enumerations
  2106. assert !IssuePriority.find(15).active?
  2107. @request.session[:user_id] = 2
  2108. get(:show, :params => {:id => 1})
  2109. assert_response :success
  2110. assert_select 'form#issue-form' do
  2111. assert_select 'select[name=?]', 'issue[priority_id]' do
  2112. assert_select 'option[value="4"]'
  2113. assert_select 'option[value="15"]', 0
  2114. end
  2115. end
  2116. end
  2117. def test_update_form_should_allow_attachment_upload
  2118. @request.session[:user_id] = 2
  2119. get(:show, :params => {:id => 1})
  2120. assert_select 'form#issue-form[method=post][enctype="multipart/form-data"]' do
  2121. assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
  2122. end
  2123. end
  2124. def test_update_form_should_render_assign_to_me_link_when_issue_can_be_assigned_to_the_current_user
  2125. @request.session[:user_id] = 1
  2126. get(
  2127. :show,
  2128. :params => {
  2129. :id => 10
  2130. }
  2131. )
  2132. assert_select 'form#issue-form #attributes' do
  2133. assert_select 'a[class=?][data-id=?]', 'assign-to-me-link', '1', 1
  2134. end
  2135. end
  2136. def test_update_form_should_not_render_assign_to_me_link_when_issue_cannot_be_assigned_to_the_current_user
  2137. @request.session[:user_id] = 1
  2138. get(
  2139. :show,
  2140. :params => {
  2141. :id => 2
  2142. }
  2143. )
  2144. assert_select 'form#issue-form #attributes' do
  2145. assert_select 'a[class=?]', 'assign-to-me-link', 0
  2146. end
  2147. end
  2148. def test_update_form_should_not_show_assign_to_me_link_when_issue_is_assigned_to_the_current_user
  2149. issue = Issue.find(10)
  2150. issue.assigned_to_id = 1
  2151. issue.save!
  2152. @request.session[:user_id] = 1
  2153. get(
  2154. :show,
  2155. :params => {
  2156. :id => 10
  2157. }
  2158. )
  2159. assert_select 'form#issue-form #attributes' do
  2160. assert_select 'a[class=?]', 'assign-to-me-link hidden', 1
  2161. end
  2162. end
  2163. def test_show_should_deny_anonymous_access_without_permission
  2164. Role.anonymous.remove_permission!(:view_issues)
  2165. get(:show, :params => {:id => 1})
  2166. assert_response :redirect
  2167. end
  2168. def test_show_should_deny_anonymous_access_to_private_issue
  2169. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2170. get(:show, :params => {:id => 1})
  2171. assert_response :redirect
  2172. end
  2173. def test_show_should_deny_non_member_access_without_permission
  2174. Role.non_member.remove_permission!(:view_issues)
  2175. @request.session[:user_id] = 9
  2176. get(:show, :params => {:id => 1})
  2177. assert_response :forbidden
  2178. end
  2179. def test_show_should_deny_non_member_access_to_private_issue
  2180. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2181. @request.session[:user_id] = 9
  2182. get(:show, :params => {:id => 1})
  2183. assert_response :forbidden
  2184. end
  2185. def test_show_should_deny_member_access_without_permission
  2186. Role.find(1).remove_permission!(:view_issues)
  2187. @request.session[:user_id] = 2
  2188. get(:show, :params => {:id => 1})
  2189. assert_response :forbidden
  2190. end
  2191. def test_show_should_deny_member_access_to_private_issue_without_permission
  2192. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2193. @request.session[:user_id] = 3
  2194. get(:show, :params => {:id => 1})
  2195. assert_response :forbidden
  2196. end
  2197. def test_show_should_allow_author_access_to_private_issue
  2198. Issue.where(:id => 1).update_all(["is_private = ?, author_id = 3", true])
  2199. @request.session[:user_id] = 3
  2200. get(:show, :params => {:id => 1})
  2201. assert_response :success
  2202. end
  2203. def test_show_should_allow_assignee_access_to_private_issue
  2204. Issue.where(:id => 1).update_all(["is_private = ?, assigned_to_id = 3", true])
  2205. @request.session[:user_id] = 3
  2206. get(:show, :params => {:id => 1})
  2207. assert_response :success
  2208. end
  2209. def test_show_should_allow_member_access_to_private_issue_with_permission
  2210. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2211. User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
  2212. @request.session[:user_id] = 3
  2213. get(:show, :params => {:id => 1})
  2214. assert_response :success
  2215. end
  2216. def test_show_should_format_related_issues_dates
  2217. with_settings :date_format => '%d/%m/%Y' do
  2218. issue = Issue.generate!(:start_date => '2018-11-29', :due_date => '2018-12-01')
  2219. IssueRelation.
  2220. create!(
  2221. :issue_from => Issue.find(1), :issue_to => issue,
  2222. :relation_type => 'relates'
  2223. )
  2224. get(:show, :params => {:id => 1})
  2225. assert_response :success
  2226. assert_select '#relations td.start_date', :text => '29/11/2018'
  2227. assert_select '#relations td.due_date', :text => '01/12/2018'
  2228. end
  2229. end
  2230. def test_show_should_not_disclose_relations_to_invisible_issues
  2231. with_settings :cross_project_issue_relations => '1' do
  2232. IssueRelation.
  2233. create!(
  2234. :issue_from => Issue.find(1),
  2235. :issue_to => Issue.find(2),
  2236. :relation_type => 'relates'
  2237. )
  2238. # Relation to a private project issue
  2239. IssueRelation.
  2240. create!(
  2241. :issue_from => Issue.find(1),
  2242. :issue_to => Issue.find(4),
  2243. :relation_type => 'relates'
  2244. )
  2245. get(:show, :params => {:id => 1})
  2246. assert_response :success
  2247. assert_select 'div#relations' do
  2248. assert_select 'a', :text => /#2$/
  2249. assert_select 'a', :text => /#4$/, :count => 0
  2250. end
  2251. end
  2252. end
  2253. def test_show_should_list_subtasks
  2254. issue = Issue.
  2255. create!(
  2256. :project_id => 1, :author_id => 1, :tracker_id => 1,
  2257. :parent_issue_id => 1, :subject => 'Child Issue'
  2258. )
  2259. get(:show, :params => {:id => 1})
  2260. assert_response :success
  2261. assert_select 'div#issue_tree' do
  2262. assert_select 'td.subject', :text => /Child Issue/
  2263. end
  2264. assert_select 'div#tab-content-history' do
  2265. assert_select 'div[id=?]', "change-#{Issue.find(1).journals.last.id}" do
  2266. assert_select 'ul.details', :text => "Subtask ##{issue.id} added"
  2267. end
  2268. end
  2269. end
  2270. def test_show_should_show_subtasks_stats
  2271. @request.session[:user_id] = 1
  2272. child1 = Issue.generate!(parent_issue_id: 1, subject: 'Open child issue')
  2273. Issue.generate!(parent_issue_id: 1, subject: 'Closed child issue', status_id: 5)
  2274. Issue.generate!(parent_issue_id: child1.id, subject: 'Open child of child')
  2275. # Issue not visible for anonymous
  2276. Issue.generate!(parent_issue_id: 1, subject: 'Private child', project_id: 5)
  2277. get(:show, params: {:id => 1})
  2278. assert_response :success
  2279. assert_select 'div#issue_tree span.issues-stat' do
  2280. assert_select 'span.badge', text: '4'
  2281. assert_select 'span.open a', text: '3 open'
  2282. assert_equal CGI.unescape(css_select('span.open a').first.attr(:href)),
  2283. "/issues?parent_id=~1&set_filter=true&status_id=o"
  2284. assert_select 'span.closed a', text: '1 closed'
  2285. assert_equal CGI.unescape(css_select('span.closed a').first.attr(:href)),
  2286. "/issues?parent_id=~1&set_filter=true&status_id=c"
  2287. end
  2288. end
  2289. def test_show_subtasks_stats_should_not_link_if_issue_has_zero_open_or_closed_subtasks
  2290. child1 = Issue.generate!(parent_issue_id: 1, subject: 'Open child issue')
  2291. get(:show, params: {:id => 1})
  2292. assert_response :success
  2293. assert_select 'div#issue_tree span.issues-stat' do
  2294. assert_select 'span.open a', text: '1 open'
  2295. assert_equal CGI.unescape(css_select('span.open a').first.attr(:href)),
  2296. "/issues?parent_id=~1&set_filter=true&status_id=o"
  2297. assert_select 'span.closed', text: '0 closed'
  2298. assert_select 'span.closed a', 0
  2299. end
  2300. end
  2301. def test_show_should_not_show_subtasks_stats_if_subtasks_are_not_visible
  2302. # Issue not visible for anonymous
  2303. Issue.generate!(parent_issue_id: 1, subject: 'Private child', project_id: 5)
  2304. get(:show, params: {:id => 1})
  2305. assert_response :success
  2306. assert_select 'div#issue_tree span.issues-stat', 0
  2307. end
  2308. def test_show_should_list_parents
  2309. issue = Issue.
  2310. create!(
  2311. :project_id => 1, :author_id => 1,
  2312. :tracker_id => 1, :parent_issue_id => 1,
  2313. :subject => 'Child Issue'
  2314. )
  2315. get(:show, :params => {:id => issue.id})
  2316. assert_response :success
  2317. assert_select 'div.subject' do
  2318. assert_select 'h3', 'Child Issue'
  2319. assert_select 'a[href="/issues/1"]'
  2320. end
  2321. end
  2322. def test_show_should_not_display_prev_next_links_without_query_in_session
  2323. get(:show, :params => {:id => 1})
  2324. assert_response :success
  2325. assert_select 'div.next-prev-links', 0
  2326. end
  2327. def test_show_should_display_prev_next_links_with_query_in_session
  2328. @request.session[:issue_query] =
  2329. {
  2330. :filters => {
  2331. 'status_id' => {
  2332. :values => [''], :operator => 'o'
  2333. }
  2334. },
  2335. :project_id => nil,
  2336. :sort => [['id', 'asc']]
  2337. }
  2338. with_settings :display_subprojects_issues => '0' do
  2339. get(:show, :params => {:id => 3})
  2340. end
  2341. assert_response :success
  2342. count = Issue.open.visible.count
  2343. # Previous and next issues for all projects
  2344. assert_select 'div.next-prev-links' do
  2345. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2346. assert_select 'a[href="/issues/5"]', :text => /Next/
  2347. assert_select 'span.position', :text => "3 of #{count}"
  2348. end
  2349. end
  2350. def test_show_should_display_prev_next_links_with_saved_query_in_session
  2351. query =
  2352. IssueQuery.create!(
  2353. :name => 'test',
  2354. :visibility => IssueQuery::VISIBILITY_PUBLIC,
  2355. :user_id => 1,
  2356. :filters => {'status_id' => {:values => ['5'], :operator => '='}},
  2357. :sort_criteria => [['id', 'asc']]
  2358. )
  2359. @request.session[:issue_query] = {:id => query.id, :project_id => nil}
  2360. get(:show, :params => {:id => 11})
  2361. assert_response :success
  2362. # Previous and next issues for all projects
  2363. assert_select 'div.next-prev-links' do
  2364. assert_select 'a[href="/issues/8"]', :text => /Previous/
  2365. assert_select 'a[href="/issues/12"]', :text => /Next/
  2366. end
  2367. end
  2368. def test_show_should_display_prev_next_links_with_query_and_sort_on_association
  2369. @request.session[:issue_query] =
  2370. {
  2371. :filters => {
  2372. 'status_id' => {
  2373. :values => [''], :operator => 'o'
  2374. }
  2375. },
  2376. :project_id => nil
  2377. }
  2378. %w(project tracker status priority author assigned_to category fixed_version).
  2379. each do |assoc_sort|
  2380. @request.session[:issue_query][:sort] = [[assoc_sort, 'asc']]
  2381. get(:show, :params => {:id => 3})
  2382. assert_response :success, "Wrong response status for #{assoc_sort} sort"
  2383. assert_select 'div.next-prev-links' do
  2384. assert_select 'a', :text => /(Previous|Next)/
  2385. end
  2386. end
  2387. end
  2388. def test_show_should_display_prev_next_links_with_project_query_in_session
  2389. @request.session[:issue_query] =
  2390. {
  2391. :filters => {
  2392. 'status_id' => {:values => [''], :operator => 'o'}
  2393. },
  2394. :project_id => 1, :sort => [['id', 'asc']]
  2395. }
  2396. with_settings :display_subprojects_issues => '0' do
  2397. get(:show, :params => {:id => 3})
  2398. end
  2399. assert_response :success
  2400. # Previous and next issues inside project
  2401. assert_select 'div.next-prev-links' do
  2402. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2403. assert_select 'a[href="/issues/7"]', :text => /Next/
  2404. end
  2405. end
  2406. def test_show_should_not_display_prev_link_for_first_issue
  2407. @request.session[:issue_query] =
  2408. {
  2409. :filters => {
  2410. 'status_id' => {:values => [''], :operator => 'o'}
  2411. },
  2412. :project_id => 1, :sort => [['id', 'asc']]
  2413. }
  2414. with_settings :display_subprojects_issues => '0' do
  2415. get(:show, :params => {:id => 1})
  2416. end
  2417. assert_response :success
  2418. assert_select 'div.next-prev-links' do
  2419. assert_select 'a', :text => /Previous/, :count => 0
  2420. assert_select 'a[href="/issues/2"]', :text => /Next/
  2421. end
  2422. end
  2423. def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
  2424. @request.session[:issue_query] =
  2425. {
  2426. :filters => {
  2427. 'status_id' => {:values => [''], :operator => 'c'}
  2428. },
  2429. :project_id => 1,
  2430. :sort => [['id', 'asc']]
  2431. }
  2432. get(:show, :params => {:id => 1})
  2433. assert_response :success
  2434. assert_select 'a', :text => /Previous/, :count => 0
  2435. assert_select 'a', :text => /Next/, :count => 0
  2436. end
  2437. def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
  2438. cf = IssueCustomField.
  2439. create!(
  2440. :name => 'User',
  2441. :is_for_all => true,
  2442. :tracker_ids => [1, 2, 3],
  2443. :field_format => 'user'
  2444. )
  2445. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
  2446. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
  2447. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
  2448. CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
  2449. query =
  2450. IssueQuery.create!(
  2451. :name => 'test',
  2452. :visibility => IssueQuery::VISIBILITY_PUBLIC,
  2453. :user_id => 1, :filters => {},
  2454. :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']]
  2455. )
  2456. @request.session[:issue_query] = {:id => query.id, :project_id => nil}
  2457. get(:show, :params => {:id => 3})
  2458. assert_response :success
  2459. assert_select 'div.next-prev-links' do
  2460. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2461. assert_select 'a[href="/issues/1"]', :text => /Next/
  2462. end
  2463. end
  2464. def test_show_should_display_prev_next_links_when_request_has_previous_and_next_issue_ids_params
  2465. get(
  2466. :show,
  2467. :params => {
  2468. :id => 1,
  2469. :prev_issue_id => 1,
  2470. :next_issue_id => 3,
  2471. :issue_position => 2,
  2472. :issue_count => 4
  2473. }
  2474. )
  2475. assert_response :success
  2476. assert_select 'div.next-prev-links' do
  2477. assert_select 'a[href="/issues/1"]', :text => /Previous/
  2478. assert_select 'a[href="/issues/3"]', :text => /Next/
  2479. assert_select 'span.position', :text => "2 of 4"
  2480. end
  2481. end
  2482. def test_show_should_display_category_field_if_categories_are_defined
  2483. Issue.update_all :category_id => nil
  2484. get(:show, :params => {:id => 1})
  2485. assert_response :success
  2486. assert_select '.attributes .category'
  2487. end
  2488. def test_show_should_not_display_category_field_if_no_categories_are_defined
  2489. Project.find(1).issue_categories.delete_all
  2490. get(:show, :params => {:id => 1})
  2491. assert_response :success
  2492. assert_select 'table.attributes .category', 0
  2493. end
  2494. def test_show_should_display_link_to_the_assigned_user
  2495. get(:show, :params => {:id => 2})
  2496. assert_response :success
  2497. assert_select '.assigned-to' do
  2498. assert_select 'a[href="/users/3"]'
  2499. end
  2500. end
  2501. def test_show_should_display_link_to_the_assigned_group
  2502. Issue.find(2).update_attribute(:assigned_to_id, 10)
  2503. get(:show, :params => {:id => 2})
  2504. assert_response :success
  2505. assert_select '.assigned-to' do
  2506. assert_select 'a[href="/groups/10"]'
  2507. end
  2508. end
  2509. def test_show_should_display_visible_changesets_from_other_projects
  2510. project = Project.find(2)
  2511. issue = project.issues.first
  2512. issue.changeset_ids = [102]
  2513. issue.save!
  2514. # changesets from other projects should be displayed even if repository
  2515. # is disabled on issue's project
  2516. project.disable_module! :repository
  2517. @request.session[:user_id] = 2
  2518. get(
  2519. :issue_tab,
  2520. :params => {
  2521. :id => issue.id,
  2522. :name => 'changesets'
  2523. },
  2524. :xhr => true
  2525. )
  2526. assert_select 'a[href=?]', '/projects/ecookbook/repository/10/revisions/3'
  2527. assert_select 'div.changeset p', :text => /eCookbook - /
  2528. end
  2529. def test_show_should_display_watchers
  2530. @request.session[:user_id] = 2
  2531. issue = Issue.find(1)
  2532. issue.add_watcher User.find(2)
  2533. issue.add_watcher Group.find(10)
  2534. get(:show, :params => {:id => 1})
  2535. assert_select 'div#watchers ul' do
  2536. assert_select 'li.user-2' do
  2537. assert_select 'a[href="/users/2"]'
  2538. assert_select 'a[class*=delete]'
  2539. end
  2540. assert_select "li.user-10" do
  2541. assert_select 'a[href="/users/10"]', false
  2542. assert_select 'a[class*=delete]'
  2543. end
  2544. end
  2545. end
  2546. def test_show_should_display_watchers_with_gravatars
  2547. @request.session[:user_id] = 2
  2548. issue = Issue.find(1)
  2549. issue.add_watcher User.find(2)
  2550. issue.add_watcher Group.find(10)
  2551. with_settings :gravatar_enabled => '1' do
  2552. get(:show, :params => {:id => 1})
  2553. end
  2554. assert_select 'div#watchers ul' do
  2555. assert_select 'li.user-2' do
  2556. assert_select 'img.gravatar[title=?]', 'John Smith'
  2557. assert_select 'a[href="/users/2"]'
  2558. assert_select 'a[class*=delete]'
  2559. end
  2560. assert_select "li.user-10" do
  2561. assert_select 'img.gravatar[title=?]', 'A Team'
  2562. assert_select 'a[href="/groups/10"]'
  2563. assert_select 'a[class*=delete]'
  2564. end
  2565. end
  2566. end
  2567. def test_show_should_mark_invalid_watchers
  2568. @request.session[:user_id] = 2
  2569. issue = Issue.find(4)
  2570. issue.add_watcher User.find(4)
  2571. get :show, :params => {:id => issue.id}
  2572. assert_response :success
  2573. assert_select 'div#watchers ul' do
  2574. assert_select 'li.user-4' do
  2575. assert_select 'span.icon-warning[title=?]', l(:notice_invalid_watcher), text: l(:notice_invalid_watcher)
  2576. end
  2577. end
  2578. end
  2579. def test_show_with_thumbnails_enabled_should_display_thumbnails
  2580. skip unless convert_installed?
  2581. @request.session[:user_id] = 2
  2582. with_settings :thumbnails_enabled => '1' do
  2583. get(:show, :params => {:id => 14})
  2584. assert_response :success
  2585. end
  2586. assert_select 'div.thumbnails' do
  2587. assert_select 'a[href="/attachments/16"]' do
  2588. assert_select 'img[src="/attachments/thumbnail/16/200"]'
  2589. end
  2590. end
  2591. end
  2592. def test_show_with_thumbnails_disabled_should_not_display_thumbnails
  2593. @request.session[:user_id] = 2
  2594. with_settings :thumbnails_enabled => '0' do
  2595. get(:show, :params => {:id => 14})
  2596. assert_response :success
  2597. end
  2598. assert_select 'div.thumbnails', 0
  2599. end
  2600. def test_show_with_multi_custom_field
  2601. field = CustomField.find(1)
  2602. field.update_attribute :multiple, true
  2603. issue = Issue.find(1)
  2604. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  2605. issue.save!
  2606. get(:show, :params => {:id => 1})
  2607. assert_response :success
  2608. assert_select ".cf_1 .value", :text => 'MySQL, Oracle'
  2609. end
  2610. def test_show_with_full_width_layout_custom_field_should_show_field_under_description
  2611. field =
  2612. IssueCustomField.
  2613. create!(
  2614. :name => 'Long text',
  2615. :field_format => 'text', :full_width_layout => '1',
  2616. :tracker_ids => [1], :is_for_all => true
  2617. )
  2618. issue = Issue.find(1)
  2619. issue.custom_field_values = {field.id => 'This is a long text'}
  2620. issue.save!
  2621. get(:show, :params => {:id => 1})
  2622. assert_response :success
  2623. # long text custom field should not be render in the attributes div
  2624. assert_select "div.attributes div.attribute.cf_#{field.id} p strong", 0
  2625. assert_select "div.attributes div.attribute.cf_#{field.id} div.value", 0
  2626. # long text custom field should be render under description field
  2627. assert_select "div.description ~ div.attribute.cf_#{field.id} p strong", :text => 'Long text'
  2628. assert_select(
  2629. "div.description ~ div.attribute.cf_#{field.id} div.value",
  2630. :text => 'This is a long text'
  2631. )
  2632. end
  2633. def test_show_custom_fields_with_full_text_formatting_should_be_rendered_using_wiki_class
  2634. half_field =
  2635. IssueCustomField.
  2636. create!(
  2637. :name => 'Half width field', :field_format => 'text',
  2638. :tracker_ids => [1], :is_for_all => true, :text_formatting => 'full'
  2639. )
  2640. full_field =
  2641. IssueCustomField.
  2642. create!(
  2643. :name => 'Full width field',
  2644. :field_format => 'text', :full_width_layout => '1',
  2645. :tracker_ids => [1], :is_for_all => true, :text_formatting => 'full'
  2646. )
  2647. issue = Issue.find(1)
  2648. issue.custom_field_values =
  2649. {full_field.id => 'This is a long text',
  2650. half_field.id => 'This is a short text'}
  2651. issue.save!
  2652. get(:show, :params => {:id => 1})
  2653. assert_response :success
  2654. assert_select "div.attribute.cf_#{half_field.id} div.value div.wiki", 1
  2655. assert_select "div.attribute.cf_#{full_field.id} div.value div.wiki", 1
  2656. end
  2657. def test_show_with_multi_user_custom_field
  2658. field =
  2659. IssueCustomField.
  2660. create!(
  2661. :name => 'Multi user',
  2662. :field_format => 'user', :multiple => true,
  2663. :tracker_ids => [1], :is_for_all => true
  2664. )
  2665. issue = Issue.find(1)
  2666. issue.custom_field_values = {field.id => ['2', '3']}
  2667. issue.save!
  2668. get(:show, :params => {:id => 1})
  2669. assert_response :success
  2670. assert_select ".cf_#{field.id} .value", :text => 'Dave Lopper, John Smith' do
  2671. assert_select 'a', :text => 'Dave Lopper'
  2672. assert_select 'a', :text => 'John Smith'
  2673. end
  2674. end
  2675. def test_show_should_not_display_default_value_for_new_custom_field
  2676. prior = Issue.generate!
  2677. field =
  2678. IssueCustomField.
  2679. generate!(
  2680. :name => 'WithDefault', :field_format => 'string',
  2681. :default_value => 'DEFAULT'
  2682. )
  2683. after = Issue.generate!
  2684. get :show, :params => {:id => prior.id}
  2685. assert_response :success
  2686. assert_select ".cf_#{field.id} .value", :text => ''
  2687. get :show, :params => {:id => after.id}
  2688. assert_response :success
  2689. assert_select ".cf_#{field.id} .value", :text => 'DEFAULT'
  2690. end
  2691. def test_show_should_display_private_notes_with_permission_only
  2692. journal =
  2693. Journal.
  2694. create!(
  2695. :journalized => Issue.find(2),
  2696. :notes => 'Privates notes',
  2697. :private_notes => true,
  2698. :user_id => 1
  2699. )
  2700. @request.session[:user_id] = 2
  2701. get(:show, :params => {:id => 2})
  2702. assert_response :success
  2703. assert_select "#change-#{journal.id}", 1
  2704. Role.find(1).remove_permission! :view_private_notes
  2705. get(:show, :params => {:id => 2})
  2706. assert_response :success
  2707. assert_select "#change-#{journal.id}", 0
  2708. end
  2709. def test_show_should_display_private_notes_created_by_current_user
  2710. User.find(3).roles_for_project(Project.find(1)).each do |role|
  2711. role.remove_permission! :view_private_notes
  2712. end
  2713. visible =
  2714. Journal.
  2715. create!(
  2716. :journalized => Issue.find(2),
  2717. :notes => 'Private notes',
  2718. :private_notes => true, :user_id => 3
  2719. )
  2720. not_visible =
  2721. Journal.create!(
  2722. :journalized => Issue.find(2),
  2723. :notes => 'Private notes',
  2724. :private_notes => true, :user_id => 1
  2725. )
  2726. @request.session[:user_id] = 3
  2727. get(:show, :params => {:id => 2})
  2728. assert_response :success
  2729. assert_select "#change-#{visible.id}", 1
  2730. assert_select "#change-#{not_visible.id}", 0
  2731. end
  2732. def test_show_should_mark_notes_as_edited_only_for_edited_notes
  2733. get :show, :params => {:id => 1}
  2734. assert_response :success
  2735. journal = Journal.find(1)
  2736. journal_title = l(:label_time_by_author, :time => format_time(journal.updated_on), :author => journal.updated_by)
  2737. assert_select "#change-1 h4 span.update-info[title=?]", journal_title, :text => '· Edited'
  2738. assert_select "#change-2 h4 span.update-info", 0
  2739. end
  2740. def test_show_atom
  2741. with_settings :text_formatting => 'textile' do
  2742. get(
  2743. :show,
  2744. :params => {
  2745. :id => 2,
  2746. :format => 'atom'
  2747. }
  2748. )
  2749. assert_response :success
  2750. assert_equal 'application/atom+xml', response.media_type
  2751. # Inline image
  2752. assert_select(
  2753. 'content',
  2754. :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
  2755. )
  2756. end
  2757. end
  2758. def test_show_export_to_pdf
  2759. issue = Issue.find(3)
  2760. assert issue.relations.any? {|r| r.other_issue(issue).visible?}
  2761. get(
  2762. :show,
  2763. :params => {
  2764. :id => 3,
  2765. :format => 'pdf'
  2766. }
  2767. )
  2768. assert_response :success
  2769. assert_equal 'application/pdf', @response.media_type
  2770. assert @response.body.starts_with?('%PDF')
  2771. end
  2772. def test_export_to_pdf_with_utf8_u_fffd
  2773. issue = Issue.generate!(:subject => "�")
  2774. ["en", "zh", "zh-TW", "ja", "ko", "ar"].each do |lang|
  2775. with_settings :default_language => lang do
  2776. get(
  2777. :show,
  2778. :params => {
  2779. :id => issue.id,
  2780. :format => 'pdf'
  2781. }
  2782. )
  2783. assert_response :success
  2784. assert_equal 'application/pdf', @response.media_type
  2785. assert @response.body.starts_with?('%PDF')
  2786. end
  2787. end
  2788. end
  2789. def test_show_export_to_pdf_with_ancestors
  2790. issue = Issue.generate!(:project_id => 1, :author_id => 2,
  2791. :tracker_id => 1, :subject => 'child',
  2792. :parent_issue_id => 1)
  2793. get(
  2794. :show,
  2795. :params => {
  2796. :id => issue.id,
  2797. :format => 'pdf'
  2798. }
  2799. )
  2800. assert_response :success
  2801. assert_equal 'application/pdf', @response.media_type
  2802. assert @response.body.starts_with?('%PDF')
  2803. end
  2804. def test_show_export_to_pdf_with_descendants
  2805. c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2806. :subject => 'child', :parent_issue_id => 1)
  2807. c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2808. :subject => 'child', :parent_issue_id => 1)
  2809. c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2810. :subject => 'child', :parent_issue_id => c1.id)
  2811. get(
  2812. :show,
  2813. :params => {
  2814. :id => 1,
  2815. :format => 'pdf'
  2816. }
  2817. )
  2818. assert_response :success
  2819. assert_equal 'application/pdf', @response.media_type
  2820. assert @response.body.starts_with?('%PDF')
  2821. end
  2822. def test_show_export_to_pdf_with_journals
  2823. get(
  2824. :show,
  2825. :params => {
  2826. :id => 1,
  2827. :format => 'pdf'
  2828. }
  2829. )
  2830. assert_response :success
  2831. assert_equal 'application/pdf', @response.media_type
  2832. assert @response.body.starts_with?('%PDF')
  2833. end
  2834. def test_show_export_to_pdf_with_private_journal
  2835. Journal.create!(
  2836. :journalized => Issue.find(1),
  2837. :notes => 'Private notes',
  2838. :private_notes => true,
  2839. :user_id => 3
  2840. )
  2841. @request.session[:user_id] = 3
  2842. get(
  2843. :show,
  2844. :params => {
  2845. :id => 1,
  2846. :format => 'pdf'
  2847. }
  2848. )
  2849. assert_response :success
  2850. assert_equal 'application/pdf', @response.media_type
  2851. assert @response.body.starts_with?('%PDF')
  2852. end
  2853. def test_show_export_to_pdf_with_changesets
  2854. [[100], [100, 101], [100, 101, 102]].each do |cs|
  2855. issue1 = Issue.find(3)
  2856. issue1.changesets = Changeset.find(cs)
  2857. issue1.save!
  2858. issue = Issue.find(3)
  2859. assert_equal issue.changesets.count, cs.size
  2860. get(
  2861. :show,
  2862. :params => {
  2863. :id => 3,
  2864. :format => 'pdf'
  2865. }
  2866. )
  2867. assert_response :success
  2868. assert_equal 'application/pdf', @response.media_type
  2869. assert @response.body.starts_with?('%PDF')
  2870. end
  2871. end
  2872. def test_show_invalid_should_respond_with_404
  2873. get(:show, :params => {:id => 999})
  2874. assert_response :not_found
  2875. end
  2876. def test_show_on_active_project_should_display_edit_links
  2877. @request.session[:user_id] = 1
  2878. get(:show, :params => {:id => 1})
  2879. assert_response :success
  2880. assert_select 'a', :text => 'Edit'
  2881. assert_select 'a', :text => 'Delete issue'
  2882. end
  2883. def test_show_on_closed_project_should_not_display_edit_links
  2884. Issue.find(1).project.close
  2885. @request.session[:user_id] = 1
  2886. get(:show, :params => {:id => 1})
  2887. assert_response :success
  2888. assert_select 'a', :text => 'Edit', :count => 0
  2889. assert_select 'a', :text => 'Delete issue', :count => 0
  2890. end
  2891. def test_show_should_not_display_history_tabs_for_issue_without_journals
  2892. @request.session[:user_id] = 1
  2893. get :show, :params => {:id => 5}
  2894. assert_response :success
  2895. assert_select '#history div.tabs', 0
  2896. assert_select '#history p.nodata', :text => 'No data to display'
  2897. end
  2898. def test_show_display_only_all_and_notes_tabs_for_issue_with_notes_only
  2899. @request.session[:user_id] = 1
  2900. get :show, :params => {:id => 14}
  2901. assert_response :success
  2902. assert_select '#history' do
  2903. assert_select 'div.tabs ul a', 2
  2904. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2905. assert_select 'div.tabs a[id=?]', 'tab-notes', :text => 'Notes'
  2906. end
  2907. end
  2908. def test_show_display_only_all_and_history_tabs_for_issue_with_history_changes_only
  2909. journal = Journal.create!(:journalized => Issue.find(5), :user_id => 1)
  2910. detail =
  2911. JournalDetail.
  2912. create!(
  2913. :journal => journal, :property => 'attr',
  2914. :prop_key => 'description',
  2915. :old_value => 'Foo', :value => 'Bar'
  2916. )
  2917. @request.session[:user_id] = 1
  2918. get :show, :params => {:id => 5}
  2919. assert_response :success
  2920. assert_select '#history' do
  2921. assert_select 'div.tabs ul a', 2
  2922. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2923. assert_select 'div.tabs a[id=?]', 'tab-properties', :text => 'Property changes'
  2924. end
  2925. end
  2926. def test_show_display_all_notes_and_history_tabs_for_issue_with_notes_and_history_changes
  2927. journal = Journal.create!(:journalized => Issue.find(6), :user_id => 1)
  2928. @request.session[:user_id] = 1
  2929. get :show, :params => {:id => 6}
  2930. assert_response :success
  2931. assert_select '#history' do
  2932. assert_select 'div.tabs ul a', 3
  2933. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2934. assert_select 'div.tabs a[id=?]', 'tab-notes', :text => 'Notes'
  2935. assert_select 'div.tabs a[id=?]', 'tab-properties', :text => 'Property changes'
  2936. end
  2937. end
  2938. def test_show_display_changesets_tab_for_issue_with_changesets
  2939. project = Project.find(2)
  2940. issue = Issue.find(9)
  2941. issue.changeset_ids = [102]
  2942. issue.save!
  2943. @request.session[:user_id] = 2
  2944. get :show, :params => {:id => issue.id}
  2945. assert_select '#history' do
  2946. assert_select 'div.tabs ul a', 1
  2947. assert_select 'div.tabs a[id=?]', 'tab-changesets', :text => 'Associated revisions'
  2948. end
  2949. end
  2950. def test_show_should_display_spent_time_tab_for_issue_with_time_entries
  2951. @request.session[:user_id] = 1
  2952. get :show, :params => {:id => 3}
  2953. assert_response :success
  2954. assert_select '#history' do
  2955. assert_select 'div.tabs ul a', 1
  2956. assert_select 'div.tabs a[id=?]', 'tab-time_entries', :text => 'Spent time'
  2957. end
  2958. get(
  2959. :issue_tab,
  2960. :params => {
  2961. :id => 3,
  2962. :name => 'time_entries'
  2963. },
  2964. :xhr => true
  2965. )
  2966. assert_response :success
  2967. assert_select 'div[id=?]', 'time-entry-3' do
  2968. assert_select 'a[title=?][href=?]', 'Edit', '/time_entries/3/edit'
  2969. assert_select 'a[title=?][href=?]', 'Delete', '/time_entries/3'
  2970. assert_select 'ul[class=?]', 'details', :text => /1.00 h/
  2971. end
  2972. end
  2973. def test_show_should_display_open_badge_for_open_issue
  2974. get :show, params: {id: 1}
  2975. assert_response :success
  2976. assert_select 'span.badge.badge-status-open', text: 'open'
  2977. end
  2978. def test_show_should_display_closed_badge_for_closed_issue
  2979. get :show, params: {id: 8}
  2980. assert_response :success
  2981. assert_select 'span.badge.badge-status-closed', text: 'closed'
  2982. end
  2983. def test_show_should_display_private_badge_for_private_issue
  2984. @request.session[:user_id] = 1
  2985. get :show, params: {id: 14}
  2986. assert_response :success
  2987. assert_select 'span.badge.badge-private', text: 'Private'
  2988. end
  2989. def test_show_should_not_display_edit_attachment_icon_for_user_without_edit_issue_permission_on_tracker
  2990. role = Role.find(2)
  2991. role.set_permission_trackers 'edit_issues', [2, 3]
  2992. role.save!
  2993. @request.session[:user_id] = 2
  2994. get :show, params: {id: 4}
  2995. assert_response :success
  2996. assert_select 'div.attachments .icon-edit', 0
  2997. end
  2998. def test_show_should_not_display_delete_attachment_icon_for_user_without_edit_issue_permission_on_tracker
  2999. role = Role.find(2)
  3000. role.set_permission_trackers 'edit_issues', [2, 3]
  3001. role.save!
  3002. @request.session[:user_id] = 2
  3003. get :show, params: {id: 4}
  3004. assert_response :success
  3005. assert_select 'div.attachments .icon-del', 0
  3006. end
  3007. def test_get_new
  3008. @request.session[:user_id] = 2
  3009. get(
  3010. :new,
  3011. :params => {
  3012. :project_id => 1,
  3013. :tracker_id => 1
  3014. }
  3015. )
  3016. assert_response :success
  3017. assert_select 'form#issue-form[action=?]', '/projects/ecookbook/issues'
  3018. assert_select 'form#issue-form' do
  3019. assert_select 'input[name=?]', 'issue[is_private]'
  3020. assert_select 'select[name=?]', 'issue[project_id]'
  3021. assert_select 'select[name=?]', 'issue[tracker_id]'
  3022. assert_select 'input[name=?]', 'issue[subject]'
  3023. assert_select 'textarea[name=?]', 'issue[description]'
  3024. assert_select 'select[name=?]', 'issue[status_id]'
  3025. assert_select 'select[name=?]', 'issue[priority_id]'
  3026. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  3027. assert_select 'select[name=?]', 'issue[category_id]'
  3028. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  3029. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  3030. assert_select 'input[name=?]', 'issue[start_date]'
  3031. assert_select 'input[name=?]', 'issue[due_date]'
  3032. assert_select 'select[name=?]', 'issue[done_ratio]'
  3033. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
  3034. assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
  3035. # Assert submit buttons
  3036. assert_select 'input[type=submit][name=?]', 'commit'
  3037. assert_select 'input[type=submit][name=?]', 'continue'
  3038. assert_select 'input[type=submit][name=?]', 'follow', 0
  3039. end
  3040. # Be sure we don't display inactive IssuePriorities
  3041. assert_not IssuePriority.find(15).active?
  3042. assert_select 'select[name=?]', 'issue[priority_id]' do
  3043. assert_select 'option[value="15"]', 0
  3044. end
  3045. end
  3046. def test_get_new_global_should_show_all_projects
  3047. @request.session[:user_id] = 1
  3048. get :new
  3049. assert_response :success
  3050. assert_select 'select[name=?]', 'issue[project_id]' do
  3051. assert_select 'option[value=?]', '1'
  3052. assert_select 'option[value=?]', '2'
  3053. end
  3054. end
  3055. def test_get_new_should_show_project_selector_for_project_with_subprojects
  3056. @request.session[:user_id] = 2
  3057. get(
  3058. :new,
  3059. :params => {
  3060. :project_id => 3,
  3061. :tracker_id => 1
  3062. }
  3063. )
  3064. assert_response :success
  3065. assert_select 'select[name="issue[project_id]"]' do
  3066. assert_select 'option', 3
  3067. assert_select 'option[value=?]', '1', :text => 'eCookbook'
  3068. assert_select 'option[value=?]', '5', :text => '  » Private child of eCookbook'
  3069. assert_select 'option[selected=selected][value=?]', '3', :text => '  » eCookbook Subproject 1'
  3070. # user_id 2 is not allowed to add issues on project_id 4 (it's not a member)
  3071. assert_select 'option[value=?]', '4', 0
  3072. end
  3073. end
  3074. def test_get_new_should_not_show_project_selector_for_project_without_subprojects
  3075. @request.session[:user_id] = 2
  3076. get(
  3077. :new,
  3078. :params => {
  3079. :project_id => 2,
  3080. :tracker_id => 1
  3081. }
  3082. )
  3083. assert_response :success
  3084. assert_select 'select[name="issue[project_id]"]', 0
  3085. end
  3086. def test_get_new_should_not_show_invalid_projects_when_issue_is_a_subtask
  3087. @request.session[:user_id] = 2
  3088. issue = Issue.find(1)
  3089. issue.parent_id = 3
  3090. issue.save
  3091. with_settings :cross_project_subtasks => 'tree' do
  3092. get(
  3093. :new,
  3094. :params => {
  3095. :project_id => 1,
  3096. :parent_issue_id => 1
  3097. }
  3098. )
  3099. end
  3100. assert_response :success
  3101. assert_select 'select[name="issue[project_id]"]' do
  3102. assert_select 'option', 3
  3103. # Onlinestore project should not be included
  3104. assert_select 'option[value=?]', '2', 0
  3105. end
  3106. end
  3107. def test_get_new_with_minimal_permissions
  3108. Role.find(1).update_attribute :permissions, [:add_issues]
  3109. WorkflowTransition.where(:role_id => 1).delete_all
  3110. @request.session[:user_id] = 2
  3111. get(
  3112. :new,
  3113. :params => {
  3114. :project_id => 1,
  3115. :tracker_id => 1
  3116. }
  3117. )
  3118. assert_response :success
  3119. assert_select 'form#issue-form' do
  3120. assert_select 'input[name=?]', 'issue[is_private]', 0
  3121. assert_select 'select[name=?]', 'issue[project_id]'
  3122. assert_select 'select[name=?]', 'issue[tracker_id]'
  3123. assert_select 'input[name=?]', 'issue[subject]'
  3124. assert_select 'textarea[name=?]', 'issue[description]'
  3125. assert_select 'select[name=?]', 'issue[status_id]'
  3126. assert_select 'select[name=?]', 'issue[priority_id]'
  3127. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  3128. assert_select 'select[name=?]', 'issue[category_id]'
  3129. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  3130. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  3131. assert_select 'input[name=?]', 'issue[start_date]'
  3132. assert_select 'input[name=?]', 'issue[due_date]'
  3133. assert_select 'select[name=?]', 'issue[done_ratio]'
  3134. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
  3135. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  3136. end
  3137. end
  3138. def test_new_without_project_id
  3139. @request.session[:user_id] = 2
  3140. get :new
  3141. assert_response :success
  3142. assert_select 'form#issue-form[action=?]', '/issues'
  3143. assert_select 'form#issue-form' do
  3144. assert_select 'select[name=?]', 'issue[project_id]'
  3145. end
  3146. end
  3147. def test_new_with_me_assigned_to_id
  3148. @request.session[:user_id] = 2
  3149. get(
  3150. :new,
  3151. :params => {
  3152. :issue => {:assigned_to_id => 'me'}
  3153. }
  3154. )
  3155. assert_response :success
  3156. assert_select 'select[name=?]', 'issue[assigned_to_id]' do
  3157. assert_select 'option[value="2"][selected=selected]'
  3158. end
  3159. end
  3160. def test_new_should_select_default_status
  3161. @request.session[:user_id] = 2
  3162. get(:new, :params => {:project_id => 1})
  3163. assert_response :success
  3164. assert_select 'select[name=?]', 'issue[status_id]' do
  3165. assert_select 'option[value="1"][selected=selected]'
  3166. end
  3167. assert_select 'input[name=was_default_status][value="1"]'
  3168. end
  3169. def test_new_should_propose_allowed_statuses
  3170. WorkflowTransition.delete_all
  3171. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3172. :old_status_id => 0, :new_status_id => 1)
  3173. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3174. :old_status_id => 0, :new_status_id => 3)
  3175. @request.session[:user_id] = 2
  3176. get(:new, :params => {:project_id => 1})
  3177. assert_response :success
  3178. assert_select 'select[name=?]', 'issue[status_id]' do
  3179. assert_select 'option[value="1"]'
  3180. assert_select 'option[value="3"]'
  3181. assert_select 'option', 2
  3182. assert_select 'option[value="1"][selected=selected]'
  3183. end
  3184. end
  3185. def test_new_should_propose_allowed_statuses_without_default_status_allowed
  3186. WorkflowTransition.delete_all
  3187. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3188. :old_status_id => 0, :new_status_id => 2)
  3189. assert_equal 1, Tracker.find(1).default_status_id
  3190. @request.session[:user_id] = 2
  3191. get(:new, :params => {:project_id => 1})
  3192. assert_response :success
  3193. assert_select 'select[name=?]', 'issue[status_id]' do
  3194. assert_select 'option[value="2"]'
  3195. assert_select 'option', 1
  3196. assert_select 'option[value="2"][selected=selected]'
  3197. end
  3198. end
  3199. def test_new_should_propose_allowed_trackers
  3200. role = Role.find(1)
  3201. role.set_permission_trackers 'add_issues', [1, 3]
  3202. role.save!
  3203. @request.session[:user_id] = 2
  3204. get(:new, :params => {:project_id => 1})
  3205. assert_response :success
  3206. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3207. assert_select 'option', 2
  3208. assert_select 'option[value="1"]'
  3209. assert_select 'option[value="3"]'
  3210. end
  3211. end
  3212. def test_new_should_default_to_first_tracker
  3213. @request.session[:user_id] = 2
  3214. get(:new, :params => {:project_id => 1})
  3215. assert_response :success
  3216. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3217. assert_select 'option', 3
  3218. assert_select 'option[value="1"][selected=selected]'
  3219. end
  3220. end
  3221. def test_new_with_parent_issue_id_should_default_to_first_tracker_without_disabled_parent_field
  3222. tracker = Tracker.find(1)
  3223. tracker.core_fields -= ['parent_issue_id']
  3224. tracker.save!
  3225. @request.session[:user_id] = 2
  3226. get(
  3227. :new,
  3228. :params => {
  3229. :project_id => 1,
  3230. :issue => {
  3231. :parent_issue_id => 1
  3232. }
  3233. }
  3234. )
  3235. assert_response :success
  3236. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3237. assert_select 'option', 2
  3238. assert_select 'option[value="2"][selected=selected]'
  3239. assert_select 'option[value="1"]', 0
  3240. end
  3241. end
  3242. def test_new_without_allowed_trackers_should_respond_with_403
  3243. role = Role.find(1)
  3244. role.set_permission_trackers 'add_issues', []
  3245. role.save!
  3246. @request.session[:user_id] = 2
  3247. get(:new, :params => {:project_id => 1})
  3248. assert_response :forbidden
  3249. end
  3250. def test_new_without_projects_should_respond_with_403
  3251. Project.delete_all
  3252. @request.session[:user_id] = 2
  3253. get :new
  3254. assert_response :forbidden
  3255. assert_select_error /no projects/
  3256. end
  3257. def test_new_without_enabled_trackers_on_projects_should_respond_with_403
  3258. Project.all.each {|p| p.trackers.clear}
  3259. @request.session[:user_id] = 2
  3260. get :new
  3261. assert_response :forbidden
  3262. assert_select_error /no projects/
  3263. end
  3264. def test_new_should_preselect_default_version
  3265. version = Version.generate!(:project_id => 1)
  3266. Project.find(1).update_attribute :default_version_id, version.id
  3267. @request.session[:user_id] = 2
  3268. get(:new, :params => {:project_id => 1})
  3269. assert_response :success
  3270. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  3271. assert_select 'option[value=?][selected=selected]', version.id.to_s
  3272. end
  3273. end
  3274. def test_get_new_with_list_custom_field
  3275. @request.session[:user_id] = 2
  3276. get(
  3277. :new,
  3278. :params => {
  3279. :project_id => 1,
  3280. :tracker_id => 1
  3281. }
  3282. )
  3283. assert_response :success
  3284. assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
  3285. assert_select 'option', 4
  3286. assert_select 'option[value=MySQL]', :text => 'MySQL'
  3287. end
  3288. end
  3289. def test_get_new_with_multi_custom_field
  3290. field = IssueCustomField.find(1)
  3291. field.update_attribute :multiple, true
  3292. @request.session[:user_id] = 2
  3293. get(
  3294. :new,
  3295. :params => {
  3296. :project_id => 1,
  3297. :tracker_id => 1
  3298. }
  3299. )
  3300. assert_response :success
  3301. assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
  3302. assert_select 'option', 3
  3303. assert_select 'option[value=MySQL]', :text => 'MySQL'
  3304. end
  3305. assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
  3306. end
  3307. def test_get_new_with_multi_user_custom_field
  3308. field =
  3309. IssueCustomField.
  3310. create!(
  3311. :name => 'Multi user', :field_format => 'user', :multiple => true,
  3312. :tracker_ids => [1], :is_for_all => true
  3313. )
  3314. @request.session[:user_id] = 2
  3315. get(
  3316. :new,
  3317. :params => {
  3318. :project_id => 1,
  3319. :tracker_id => 1
  3320. }
  3321. )
  3322. assert_response :success
  3323. assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
  3324. assert_select 'option', Project.find(1).users.count + 1 # users + 'me'
  3325. assert_select 'option[value="2"]', :text => 'John Smith'
  3326. end
  3327. assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
  3328. end
  3329. def test_get_new_with_date_custom_field
  3330. field = IssueCustomField.create!(:name => 'Date', :field_format => 'date',
  3331. :tracker_ids => [1], :is_for_all => true)
  3332. @request.session[:user_id] = 2
  3333. get(
  3334. :new,
  3335. :params => {
  3336. :project_id => 1,
  3337. :tracker_id => 1
  3338. }
  3339. )
  3340. assert_response :success
  3341. assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
  3342. end
  3343. def test_get_new_with_text_custom_field
  3344. field = IssueCustomField.create!(:name => 'Text', :field_format => 'text',
  3345. :tracker_ids => [1], :is_for_all => true)
  3346. @request.session[:user_id] = 2
  3347. get(
  3348. :new,
  3349. :params => {
  3350. :project_id => 1,
  3351. :tracker_id => 1
  3352. }
  3353. )
  3354. assert_response :success
  3355. assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
  3356. end
  3357. def test_get_new_without_default_start_date_is_creation_date
  3358. with_settings :default_issue_start_date_to_creation_date => 0 do
  3359. @request.session[:user_id] = 2
  3360. get(
  3361. :new,
  3362. :params => {
  3363. :project_id => 1,
  3364. :tracker_id => 1
  3365. }
  3366. )
  3367. assert_response :success
  3368. assert_select 'input[name=?]', 'issue[start_date]'
  3369. assert_select 'input[name=?][value]', 'issue[start_date]', 0
  3370. end
  3371. end
  3372. def test_get_new_with_default_start_date_is_creation_date
  3373. with_settings :default_issue_start_date_to_creation_date => 1 do
  3374. @request.session[:user_id] = 2
  3375. get(
  3376. :new,
  3377. :params => {
  3378. :project_id => 1,
  3379. :tracker_id => 1
  3380. }
  3381. )
  3382. assert_response :success
  3383. assert_select 'input[name=?][value=?]', 'issue[start_date]',
  3384. Date.today.to_s
  3385. end
  3386. end
  3387. def test_get_new_form_should_allow_attachment_upload
  3388. @request.session[:user_id] = 2
  3389. get(
  3390. :new,
  3391. :params => {
  3392. :project_id => 1,
  3393. :tracker_id => 1
  3394. }
  3395. )
  3396. assert_response :success
  3397. assert_select 'form[id=issue-form][method=post][enctype="multipart/form-data"]' do
  3398. assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
  3399. end
  3400. end
  3401. def test_get_new_should_prefill_the_form_from_params
  3402. @request.session[:user_id] = 2
  3403. get(
  3404. :new,
  3405. :params => {
  3406. :project_id => 1,
  3407. :issue => {
  3408. :tracker_id => 3,
  3409. :description => 'Prefilled',
  3410. :custom_field_values => {
  3411. '2' => 'Custom field value'
  3412. }
  3413. }
  3414. }
  3415. )
  3416. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3417. assert_select 'option[value="3"][selected=selected]'
  3418. end
  3419. assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
  3420. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
  3421. end
  3422. def test_get_new_should_mark_required_fields
  3423. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  3424. :is_for_all => true, :tracker_ids => [1, 2])
  3425. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  3426. :is_for_all => true, :tracker_ids => [1, 2])
  3427. WorkflowPermission.delete_all
  3428. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
  3429. :field_name => 'due_date', :rule => 'required')
  3430. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
  3431. :field_name => cf2.id.to_s, :rule => 'required')
  3432. @request.session[:user_id] = 2
  3433. get(:new, :params => {:project_id => 1})
  3434. assert_response :success
  3435. assert_select 'label[for=issue_start_date]' do
  3436. assert_select 'span[class=required]', 0
  3437. end
  3438. assert_select 'label[for=issue_due_date]' do
  3439. assert_select 'span[class=required]'
  3440. end
  3441. assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
  3442. assert_select 'span[class=required]', 0
  3443. end
  3444. assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
  3445. assert_select 'span[class=required]'
  3446. end
  3447. end
  3448. def test_get_new_should_not_display_readonly_fields
  3449. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  3450. :is_for_all => true, :tracker_ids => [1, 2])
  3451. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  3452. :is_for_all => true, :tracker_ids => [1, 2])
  3453. WorkflowPermission.delete_all
  3454. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
  3455. :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
  3456. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
  3457. :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
  3458. @request.session[:user_id] = 2
  3459. get(:new, :params => {:project_id => 1})
  3460. assert_response :success
  3461. assert_select 'input[name=?]', 'issue[start_date]'
  3462. assert_select 'input[name=?]', 'issue[due_date]', 0
  3463. assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
  3464. assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
  3465. end
  3466. def test_new_with_tracker_set_as_readonly_should_accept_status
  3467. WorkflowPermission.delete_all
  3468. [1, 2].each do |status_id|
  3469. WorkflowPermission.
  3470. create!(
  3471. :tracker_id => 1,
  3472. :old_status_id => status_id,
  3473. :role_id => 1,
  3474. :field_name => 'tracker_id',
  3475. :rule => 'readonly'
  3476. )
  3477. end
  3478. @request.session[:user_id] = 2
  3479. get(
  3480. :new,
  3481. :params => {
  3482. :project_id => 1,
  3483. :issue => {
  3484. :status_id => 2
  3485. }
  3486. }
  3487. )
  3488. assert_select 'select[name=?]', 'issue[tracker_id]', 0
  3489. assert_select 'select[name=?]', 'issue[status_id]' do
  3490. assert_select 'option[value=?][selected=selected]', '2'
  3491. end
  3492. end
  3493. def test_get_new_without_tracker_id
  3494. @request.session[:user_id] = 2
  3495. get(
  3496. :new,
  3497. :params => {
  3498. :project_id => 1
  3499. }
  3500. )
  3501. assert_response :success
  3502. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3503. assert_select 'option[value=?][selected=selected]', Project.find(1).trackers.first.id.to_s
  3504. end
  3505. end
  3506. def test_get_new_with_no_default_status_should_display_an_error
  3507. @request.session[:user_id] = 2
  3508. IssueStatus.delete_all
  3509. get(
  3510. :new,
  3511. :params => {
  3512. :project_id => 1
  3513. }
  3514. )
  3515. assert_response :internal_server_error
  3516. assert_select_error /No default issue/
  3517. end
  3518. def test_get_new_with_no_tracker_should_display_an_error
  3519. @request.session[:user_id] = 2
  3520. Tracker.delete_all
  3521. get(
  3522. :new,
  3523. :params => {
  3524. :project_id => 1
  3525. }
  3526. )
  3527. assert_response :internal_server_error
  3528. assert_select_error /No tracker/
  3529. end
  3530. def test_new_with_invalid_project_id
  3531. @request.session[:user_id] = 1
  3532. get(
  3533. :new,
  3534. :params => {
  3535. :project_id => 'invalid'
  3536. }
  3537. )
  3538. assert_response :not_found
  3539. end
  3540. def test_new_with_parent_id_should_only_propose_valid_trackers
  3541. @request.session[:user_id] = 2
  3542. t = Tracker.find(3)
  3543. assert !t.disabled_core_fields.include?('parent_issue_id')
  3544. get(
  3545. :new,
  3546. :params => {
  3547. :project_id => 1, :issue => {:parent_issue_id => 1}
  3548. }
  3549. )
  3550. assert_response :success
  3551. assert_select 'option', text: /#{t.name}/, count: 1
  3552. t.core_fields = Tracker::CORE_FIELDS - ['parent_issue_id']
  3553. t.save!
  3554. assert t.disabled_core_fields.include?('parent_issue_id')
  3555. get(
  3556. :new,
  3557. :params => {
  3558. :project_id => 1, :issue => {:parent_issue_id => 1}
  3559. }
  3560. )
  3561. assert_response :success
  3562. assert_select 'option', text: /#{t.name}/, count: 0
  3563. end
  3564. def test_get_new_should_show_trackers_description
  3565. @request.session[:user_id] = 2
  3566. get :new, :params => {
  3567. :project_id => 1,
  3568. :issue => {
  3569. :tracker_id => 1
  3570. }
  3571. }
  3572. assert_response :success
  3573. assert_select 'form#issue-form' do
  3574. assert_select 'a[title=?]', 'View all trackers description', :text => 'View all trackers description'
  3575. assert_select 'select[name=?][title=?]', 'issue[tracker_id]', 'Description for Bug tracker'
  3576. end
  3577. assert_select 'div#trackers_description' do
  3578. assert_select 'h3', :text => 'Trackers description', :count => 1
  3579. # only Bug and Feature have descriptions
  3580. assert_select 'dt', 2
  3581. assert_select 'dt', :text => 'Bug', :count => 1
  3582. assert_select 'dd', :text => 'Description for Bug tracker', :count => 1
  3583. end
  3584. end
  3585. def test_get_new_should_not_show_trackers_description_for_trackers_without_description
  3586. Tracker.update_all(:description => '')
  3587. @request.session[:user_id] = 2
  3588. get :new, :params => {
  3589. :project_id => 1,
  3590. :issue => {
  3591. :tracker_id => 1
  3592. }
  3593. }
  3594. assert_response :success
  3595. assert_select 'form#issue-form' do
  3596. assert_select 'a[title=?]', 'View all trackers description', 0
  3597. assert_select 'select[name=?][title=?]', 'issue[tracker_id]', ''
  3598. end
  3599. assert_select 'div#trackers_description', 0
  3600. end
  3601. def test_get_new_should_show_issue_status_description
  3602. @request.session[:user_id] = 2
  3603. get :new, :params => {
  3604. :project_id => 1,
  3605. :issue => {
  3606. :status_id => 2
  3607. }
  3608. }
  3609. assert_response :success
  3610. assert_select 'form#issue-form' do
  3611. assert_select 'a[title=?]', 'View all issue statuses description', :text => 'View all issue statuses description'
  3612. assert_select 'select[name=?][title=?]', 'issue[status_id]', 'Description for Assigned issue status'
  3613. end
  3614. assert_select 'div#issue_statuses_description' do
  3615. assert_select 'h3', :text => 'Issue statuses description', :count => 1
  3616. assert_select 'dt', 2
  3617. assert_select 'dt', :text => 'New', :count => 1
  3618. assert_select 'dd', :text => 'Description for New issue status', :count => 1
  3619. end
  3620. end
  3621. def test_get_new_should_not_show_issue_status_description
  3622. IssueStatus.update_all(:description => '')
  3623. @request.session[:user_id] = 2
  3624. get :new, :params => {
  3625. :project_id => 1,
  3626. :issue => {
  3627. :status_id => 2
  3628. }
  3629. }
  3630. assert_response :success
  3631. assert_select 'form#issue-form' do
  3632. assert_select 'a[title=?]', 'View all issue statuses description', 0
  3633. assert_select 'select[name=?][title=?]', 'issue[status_id]', ''
  3634. end
  3635. assert_select 'div#issue_statuses_description', 0
  3636. end
  3637. def test_get_new_should_show_create_and_follow_button_when_issue_is_subtask_and_back_url_is_present
  3638. @request.session[:user_id] = 2
  3639. get :new, params: {
  3640. project_id: 1,
  3641. issue: {
  3642. parent_issue_id: 2
  3643. },
  3644. back_url: "/issues/2"
  3645. }
  3646. assert_response :success
  3647. assert_select 'form#issue-form' do
  3648. # Assert submit buttons
  3649. assert_select 'input[type=submit][name=?]', 'commit'
  3650. assert_select 'input[type=submit][name=?]', 'continue'
  3651. assert_select 'input[type=submit][name=?]', 'follow'
  3652. end
  3653. end
  3654. def test_update_form_for_new_issue
  3655. @request.session[:user_id] = 2
  3656. post(
  3657. :new,
  3658. :params => {
  3659. :project_id => 1,
  3660. :issue => {
  3661. :tracker_id => 2,
  3662. :subject => 'This is the test_new issue',
  3663. :description => 'This is the description',
  3664. :priority_id => 5
  3665. }
  3666. },
  3667. :xhr => true
  3668. )
  3669. assert_response :success
  3670. assert_equal 'text/javascript', response.media_type
  3671. assert_include 'This is the test_new issue', response.body
  3672. end
  3673. def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
  3674. @request.session[:user_id] = 2
  3675. WorkflowTransition.delete_all
  3676. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3677. :old_status_id => 0, :new_status_id => 2)
  3678. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3679. :old_status_id => 0, :new_status_id => 5)
  3680. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3681. :old_status_id => 5, :new_status_id => 4)
  3682. post(
  3683. :new,
  3684. :params => {
  3685. :project_id => 1,
  3686. :issue => {
  3687. :tracker_id => 1,
  3688. :status_id => 5,
  3689. :subject => 'This is an issue'
  3690. }
  3691. }
  3692. )
  3693. assert_select 'select[name=?]', 'issue[status_id]' do
  3694. assert_select 'option[value=?][selected=selected]', '5'
  3695. assert_select 'option[value=?]', '2'
  3696. assert_select 'option', :count => 2
  3697. end
  3698. end
  3699. def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
  3700. @request.session[:user_id] = 2
  3701. tracker = Tracker.find(2)
  3702. tracker.update! :default_status_id => 2
  3703. tracker.generate_transitions! 2 => 1, :clear => true
  3704. post(
  3705. :new,
  3706. :params => {
  3707. :project_id => 1,
  3708. :issue => {
  3709. :tracker_id => 2,
  3710. :status_id => 1
  3711. },
  3712. :was_default_status => 1
  3713. }
  3714. )
  3715. assert_response :success
  3716. assert_select 'select[name=?]', 'issue[status_id]' do
  3717. assert_select 'option[value=?][selected=selected]', '2'
  3718. end
  3719. end
  3720. def test_update_form_for_new_issue_should_ignore_version_when_changing_project
  3721. version = Version.generate!(:project_id => 1)
  3722. Project.find(1).update_attribute :default_version_id, version.id
  3723. @request.session[:user_id] = 2
  3724. post(
  3725. :new,
  3726. :params => {
  3727. :issue => {
  3728. :project_id => 1,
  3729. :fixed_version_id => ''
  3730. },
  3731. :form_update_triggered_by => 'issue_project_id'
  3732. }
  3733. )
  3734. assert_response :success
  3735. assert_select 'select[name=?]', 'issue[project_id]' do
  3736. assert_select 'option[value=?][selected=selected]', '1'
  3737. end
  3738. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  3739. assert_select 'option[value=?][selected=selected]', version.id.to_s
  3740. end
  3741. end
  3742. def test_post_create
  3743. @request.session[:user_id] = 2
  3744. assert_difference 'Issue.count' do
  3745. assert_no_difference 'Journal.count' do
  3746. post(
  3747. :create,
  3748. :params => {
  3749. :project_id => 1,
  3750. :issue => {
  3751. :tracker_id => 3,
  3752. :status_id => 2,
  3753. :subject => 'This is the test_new issue',
  3754. :description => 'This is the description',
  3755. :priority_id => 5,
  3756. :start_date => '2010-11-07',
  3757. :estimated_hours => '',
  3758. :custom_field_values => {
  3759. '2' => 'Value for field 2'
  3760. }
  3761. }
  3762. }
  3763. )
  3764. end
  3765. end
  3766. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3767. issue = Issue.find_by_subject('This is the test_new issue')
  3768. assert_not_nil issue
  3769. assert_equal 2, issue.author_id
  3770. assert_equal 3, issue.tracker_id
  3771. assert_equal 2, issue.status_id
  3772. assert_equal Date.parse('2010-11-07'), issue.start_date
  3773. assert_nil issue.estimated_hours
  3774. v = issue.custom_values.where(:custom_field_id => 2).first
  3775. assert_not_nil v
  3776. assert_equal 'Value for field 2', v.value
  3777. end
  3778. def test_post_new_with_group_assignment
  3779. group = Group.find(11)
  3780. project = Project.find(1)
  3781. project.members << Member.new(:principal => group, :roles => [Role.givable.first])
  3782. with_settings :issue_group_assignment => '1' do
  3783. @request.session[:user_id] = 2
  3784. assert_difference 'Issue.count' do
  3785. post(
  3786. :create,
  3787. :params => {
  3788. :project_id => project.id,
  3789. :issue => {
  3790. :tracker_id => 3,
  3791. :status_id => 1,
  3792. :subject => 'This is the test_new_with_group_assignment issue',
  3793. :assigned_to_id => group.id
  3794. }
  3795. }
  3796. )
  3797. end
  3798. end
  3799. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3800. issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
  3801. assert_not_nil issue
  3802. assert_equal group, issue.assigned_to
  3803. end
  3804. def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
  3805. with_settings :default_issue_start_date_to_creation_date => 0 do
  3806. @request.session[:user_id] = 2
  3807. assert_difference 'Issue.count' do
  3808. post(
  3809. :create,
  3810. :params => {
  3811. :project_id => 1,
  3812. :issue => {
  3813. :tracker_id => 3,
  3814. :status_id => 2,
  3815. :subject => 'This is the test_new issue',
  3816. :description => 'This is the description',
  3817. :priority_id => 5,
  3818. :estimated_hours => '',
  3819. :custom_field_values => {
  3820. '2' => 'Value for field 2'
  3821. }
  3822. }
  3823. }
  3824. )
  3825. end
  3826. assert_redirected_to :controller => 'issues', :action => 'show',
  3827. :id => Issue.last.id
  3828. issue = Issue.find_by_subject('This is the test_new issue')
  3829. assert_not_nil issue
  3830. assert_nil issue.start_date
  3831. end
  3832. end
  3833. def test_post_create_without_start_date_and_default_start_date_is_creation_date
  3834. with_settings :default_issue_start_date_to_creation_date => 1 do
  3835. @request.session[:user_id] = 2
  3836. assert_difference 'Issue.count' do
  3837. post(
  3838. :create,
  3839. :params => {
  3840. :project_id => 1,
  3841. :issue => {
  3842. :tracker_id => 3,
  3843. :status_id => 2,
  3844. :subject => 'This is the test_new issue',
  3845. :description => 'This is the description',
  3846. :priority_id => 5,
  3847. :estimated_hours => '',
  3848. :custom_field_values => {
  3849. '2' => 'Value for field 2'
  3850. }
  3851. }
  3852. }
  3853. )
  3854. end
  3855. assert_redirected_to :controller => 'issues', :action => 'show',
  3856. :id => Issue.last.id
  3857. issue = Issue.find_by_subject('This is the test_new issue')
  3858. assert_not_nil issue
  3859. assert_equal Date.today, issue.start_date
  3860. end
  3861. end
  3862. def test_post_create_and_continue
  3863. @request.session[:user_id] = 2
  3864. assert_difference 'Issue.count' do
  3865. post(
  3866. :create,
  3867. :params => {
  3868. :project_id => 1,
  3869. :issue => {
  3870. :tracker_id => 3,
  3871. :subject => 'This is first issue',
  3872. :priority_id => 5
  3873. },
  3874. :continue => ''
  3875. }
  3876. )
  3877. end
  3878. issue = Issue.order('id DESC').first
  3879. assert_redirected_to :controller => 'issues',
  3880. :action => 'new', :project_id => 'ecookbook',
  3881. :issue => {:tracker_id => 3}
  3882. assert_not_nil flash[:notice], "flash was not set"
  3883. assert_select_in flash[:notice],
  3884. 'a[href=?][title=?]', "/issues/#{issue.id}",
  3885. "This is first issue", :text => "##{issue.id}"
  3886. end
  3887. def test_post_create_without_custom_fields_param
  3888. @request.session[:user_id] = 2
  3889. assert_difference 'Issue.count' do
  3890. post(
  3891. :create,
  3892. :params => {
  3893. :project_id => 1,
  3894. :issue => {
  3895. :tracker_id => 1,
  3896. :subject => 'This is the test_new issue',
  3897. :description => 'This is the description',
  3898. :priority_id => 5
  3899. }
  3900. }
  3901. )
  3902. end
  3903. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3904. end
  3905. def test_post_create_with_multi_custom_field
  3906. field = IssueCustomField.find_by_name('Database')
  3907. field.update_attribute(:multiple, true)
  3908. @request.session[:user_id] = 2
  3909. assert_difference 'Issue.count' do
  3910. post(
  3911. :create,
  3912. :params => {
  3913. :project_id => 1,
  3914. :issue => {
  3915. :tracker_id => 1,
  3916. :subject => 'This is the test_new issue',
  3917. :description => 'This is the description',
  3918. :priority_id => 5,
  3919. :custom_field_values => {
  3920. '1' => ['', 'MySQL', 'Oracle']
  3921. }
  3922. }
  3923. }
  3924. )
  3925. end
  3926. assert_response :found
  3927. issue = Issue.order('id DESC').first
  3928. assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
  3929. end
  3930. def test_post_create_with_empty_multi_custom_field
  3931. field = IssueCustomField.find_by_name('Database')
  3932. field.update_attribute(:multiple, true)
  3933. @request.session[:user_id] = 2
  3934. assert_difference 'Issue.count' do
  3935. post(
  3936. :create,
  3937. :params => {
  3938. :project_id => 1,
  3939. :issue => {
  3940. :tracker_id => 1,
  3941. :subject => 'This is the test_new issue',
  3942. :description => 'This is the description',
  3943. :priority_id => 5,
  3944. :custom_field_values => {
  3945. '1' => ['']
  3946. }
  3947. }
  3948. }
  3949. )
  3950. end
  3951. assert_response :found
  3952. issue = Issue.order('id DESC').first
  3953. assert_equal [''], issue.custom_field_value(1).sort
  3954. end
  3955. def test_post_create_with_multi_user_custom_field
  3956. field =
  3957. IssueCustomField.create!(:name => 'Multi user', :field_format => 'user',
  3958. :multiple => true,
  3959. :tracker_ids => [1], :is_for_all => true)
  3960. @request.session[:user_id] = 2
  3961. assert_difference 'Issue.count' do
  3962. post(
  3963. :create,
  3964. :params => {
  3965. :project_id => 1,
  3966. :issue => {
  3967. :tracker_id => 1,
  3968. :subject => 'This is the test_new issue',
  3969. :description => 'This is the description',
  3970. :priority_id => 5,
  3971. :custom_field_values => {
  3972. field.id.to_s => ['', '2', '3']
  3973. }
  3974. }
  3975. }
  3976. )
  3977. end
  3978. assert_response :found
  3979. issue = Issue.order('id DESC').first
  3980. assert_equal ['2', '3'], issue.custom_field_value(field).sort
  3981. end
  3982. def test_post_create_with_required_custom_field_and_without_custom_fields_param
  3983. field = IssueCustomField.find_by_name('Database')
  3984. field.update_attribute(:is_required, true)
  3985. @request.session[:user_id] = 2
  3986. assert_no_difference 'Issue.count' do
  3987. post(
  3988. :create,
  3989. :params => {
  3990. :project_id => 1,
  3991. :issue => {
  3992. :tracker_id => 1,
  3993. :subject => 'This is the test_new issue',
  3994. :description => 'This is the description',
  3995. :priority_id => 5
  3996. }
  3997. }
  3998. )
  3999. end
  4000. assert_response :success
  4001. assert_select 'label[for=?][class=?]', "issue_custom_field_values_#{field.id}", 'error'
  4002. assert_select_error /Database cannot be blank/
  4003. end
  4004. def test_create_should_validate_required_fields
  4005. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  4006. :is_for_all => true, :tracker_ids => [1, 2])
  4007. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  4008. :is_for_all => true, :tracker_ids => [1, 2])
  4009. WorkflowPermission.delete_all
  4010. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4011. :field_name => 'due_date', :rule => 'required')
  4012. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4013. :field_name => cf2.id.to_s, :rule => 'required')
  4014. @request.session[:user_id] = 2
  4015. assert_no_difference 'Issue.count' do
  4016. post(
  4017. :create,
  4018. :params => {
  4019. :project_id => 1,
  4020. :issue => {
  4021. :tracker_id => 2,
  4022. :status_id => 1,
  4023. :subject => 'Test',
  4024. :start_date => '',
  4025. :due_date => '',
  4026. :custom_field_values => {
  4027. cf1.id.to_s => '', cf2.id.to_s => ''
  4028. }
  4029. }
  4030. }
  4031. )
  4032. assert_response :success
  4033. end
  4034. assert_select 'label[for=?][class=?]', 'issue_due_date', 'error'
  4035. assert_select 'label[for=?][class=?]', "issue_custom_field_values_#{cf2.id}", 'error'
  4036. assert_select_error /Due date cannot be blank/i
  4037. assert_select_error /Bar cannot be blank/i
  4038. end
  4039. def test_create_should_validate_required_list_fields
  4040. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'list',
  4041. :is_for_all => true, :tracker_ids => [1, 2],
  4042. :multiple => false, :possible_values => ['a', 'b'])
  4043. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'list',
  4044. :is_for_all => true, :tracker_ids => [1, 2],
  4045. :multiple => true, :possible_values => ['a', 'b'])
  4046. WorkflowPermission.delete_all
  4047. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4048. :field_name => cf1.id.to_s, :rule => 'required')
  4049. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4050. :field_name => cf2.id.to_s, :rule => 'required')
  4051. @request.session[:user_id] = 2
  4052. assert_no_difference 'Issue.count' do
  4053. post(
  4054. :create,
  4055. :params => {
  4056. :project_id => 1,
  4057. :issue => {
  4058. :tracker_id => 2,
  4059. :status_id => 1,
  4060. :subject => 'Test',
  4061. :start_date => '',
  4062. :due_date => '',
  4063. :custom_field_values => {
  4064. cf1.id.to_s => '', cf2.id.to_s => ['']
  4065. }
  4066. }
  4067. }
  4068. )
  4069. assert_response :success
  4070. end
  4071. assert_select_error /Foo cannot be blank/i
  4072. assert_select_error /Bar cannot be blank/i
  4073. end
  4074. def test_create_should_ignore_readonly_fields
  4075. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  4076. :is_for_all => true, :tracker_ids => [1, 2])
  4077. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  4078. :is_for_all => true, :tracker_ids => [1, 2])
  4079. WorkflowPermission.delete_all
  4080. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4081. :field_name => 'due_date', :rule => 'readonly')
  4082. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4083. :field_name => cf2.id.to_s, :rule => 'readonly')
  4084. @request.session[:user_id] = 2
  4085. assert_difference 'Issue.count' do
  4086. post(
  4087. :create,
  4088. :params => {
  4089. :project_id => 1,
  4090. :issue => {
  4091. :tracker_id => 2,
  4092. :status_id => 1,
  4093. :subject => 'Test',
  4094. :start_date => '2012-07-14',
  4095. :due_date => '2012-07-16',
  4096. :custom_field_values => {
  4097. cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
  4098. }
  4099. }
  4100. }
  4101. )
  4102. assert_response :found
  4103. end
  4104. issue = Issue.order('id DESC').first
  4105. assert_equal Date.parse('2012-07-14'), issue.start_date
  4106. assert_nil issue.due_date
  4107. assert_equal 'value1', issue.custom_field_value(cf1)
  4108. assert_nil issue.custom_field_value(cf2)
  4109. end
  4110. def test_create_should_ignore_unallowed_trackers
  4111. role = Role.find(1)
  4112. role.set_permission_trackers :add_issues, [3]
  4113. role.save!
  4114. @request.session[:user_id] = 2
  4115. issue = new_record(Issue) do
  4116. post(
  4117. :create,
  4118. :params => {
  4119. :project_id => 1,
  4120. :issue => {
  4121. :tracker_id => 1,
  4122. :status_id => 1,
  4123. :subject => 'Test'
  4124. }
  4125. }
  4126. )
  4127. assert_response :found
  4128. end
  4129. assert_equal 3, issue.tracker_id
  4130. end
  4131. def test_post_create_with_watchers
  4132. @request.session[:user_id] = 2
  4133. ActionMailer::Base.deliveries.clear
  4134. with_settings :notified_events => %w(issue_added) do
  4135. assert_difference 'Watcher.count', 3 do
  4136. post(
  4137. :create,
  4138. :params => {
  4139. :project_id => 1,
  4140. :issue => {
  4141. :tracker_id => 1,
  4142. :subject => 'This is a new issue with watchers',
  4143. :description => 'This is the description',
  4144. :priority_id => 5,
  4145. :watcher_user_ids => ['2', '3', '10']
  4146. }
  4147. }
  4148. )
  4149. end
  4150. end
  4151. issue = Issue.find_by_subject('This is a new issue with watchers')
  4152. assert_not_nil issue
  4153. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
  4154. # Watchers added
  4155. assert_equal [2, 3, 10], issue.watcher_user_ids.sort
  4156. assert issue.watched_by?(User.find(3))
  4157. assert issue.watched_by?(Group.find(10))
  4158. # Watchers notified
  4159. assert_equal 3, ActionMailer::Base.deliveries.size
  4160. mail = ActionMailer::Base.deliveries[1]
  4161. assert [mail.to].flatten.include?(User.find(3).mail)
  4162. mail = ActionMailer::Base.deliveries[2]
  4163. assert [mail.to].flatten.include?(User.find(8).mail)
  4164. end
  4165. def test_post_create_subissue
  4166. @request.session[:user_id] = 2
  4167. assert_difference 'Issue.count' do
  4168. post(
  4169. :create,
  4170. :params => {
  4171. :project_id => 1,
  4172. :issue => {
  4173. :tracker_id => 1,
  4174. :subject => 'This is a child issue',
  4175. :parent_issue_id => '2'
  4176. }
  4177. }
  4178. )
  4179. assert_response :found
  4180. end
  4181. issue = Issue.order('id DESC').first
  4182. assert_equal Issue.find(2), issue.parent
  4183. end
  4184. def test_post_create_subissue_with_sharp_parent_id
  4185. @request.session[:user_id] = 2
  4186. assert_difference 'Issue.count' do
  4187. post(
  4188. :create,
  4189. :params => {
  4190. :project_id => 1,
  4191. :issue => {
  4192. :tracker_id => 1,
  4193. :subject => 'This is a child issue',
  4194. :parent_issue_id => '#2'
  4195. }
  4196. }
  4197. )
  4198. assert_response :found
  4199. end
  4200. issue = Issue.order('id DESC').first
  4201. assert_equal Issue.find(2), issue.parent
  4202. end
  4203. def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
  4204. @request.session[:user_id] = 2
  4205. assert_no_difference 'Issue.count' do
  4206. post(
  4207. :create,
  4208. :params => {
  4209. :project_id => 1,
  4210. :issue => {
  4211. :tracker_id => 1,
  4212. :subject => 'This is a child issue',
  4213. :parent_issue_id => '4'
  4214. }
  4215. }
  4216. )
  4217. assert_response :success
  4218. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
  4219. assert_select_error /Parent task is invalid/i
  4220. end
  4221. end
  4222. def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
  4223. @request.session[:user_id] = 2
  4224. assert_no_difference 'Issue.count' do
  4225. post(
  4226. :create,
  4227. :params => {
  4228. :project_id => 1,
  4229. :issue => {
  4230. :tracker_id => 1,
  4231. :subject => 'This is a child issue',
  4232. :parent_issue_id => '01ABC'
  4233. }
  4234. }
  4235. )
  4236. assert_response :success
  4237. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
  4238. assert_select_error /Parent task is invalid/i
  4239. end
  4240. end
  4241. def test_post_create_private
  4242. @request.session[:user_id] = 2
  4243. assert_difference 'Issue.count' do
  4244. post(
  4245. :create,
  4246. :params => {
  4247. :project_id => 1,
  4248. :issue => {
  4249. :tracker_id => 1,
  4250. :subject => 'This is a private issue',
  4251. :is_private => '1'
  4252. }
  4253. }
  4254. )
  4255. end
  4256. issue = Issue.order('id DESC').first
  4257. assert issue.is_private?
  4258. end
  4259. def test_post_create_private_with_set_own_issues_private_permission
  4260. role = Role.find(1)
  4261. role.remove_permission! :set_issues_private
  4262. role.add_permission! :set_own_issues_private
  4263. @request.session[:user_id] = 2
  4264. assert_difference 'Issue.count' do
  4265. post(
  4266. :create,
  4267. :params => {
  4268. :project_id => 1,
  4269. :issue => {
  4270. :tracker_id => 1,
  4271. :subject => 'This is a private issue',
  4272. :is_private => '1'
  4273. }
  4274. }
  4275. )
  4276. end
  4277. issue = Issue.order('id DESC').first
  4278. assert issue.is_private?
  4279. end
  4280. def test_create_without_project_id
  4281. @request.session[:user_id] = 2
  4282. assert_difference 'Issue.count' do
  4283. post(
  4284. :create,
  4285. :params => {
  4286. :issue => {
  4287. :project_id => 3,
  4288. :tracker_id => 2,
  4289. :subject => 'Foo'
  4290. }
  4291. }
  4292. )
  4293. assert_response :found
  4294. end
  4295. issue = Issue.order('id DESC').first
  4296. assert_equal 3, issue.project_id
  4297. assert_equal 2, issue.tracker_id
  4298. end
  4299. def test_create_without_project_id_and_continue_should_redirect_without_project_id
  4300. @request.session[:user_id] = 2
  4301. assert_difference 'Issue.count' do
  4302. post(
  4303. :create,
  4304. :params => {
  4305. :issue => {
  4306. :project_id => 3,
  4307. :tracker_id => 2,
  4308. :subject => 'Foo'
  4309. },
  4310. :continue => '1'
  4311. }
  4312. )
  4313. assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
  4314. end
  4315. end
  4316. def test_create_without_project_id_should_be_denied_without_permission
  4317. Role.non_member.remove_permission! :add_issues
  4318. Role.anonymous.remove_permission! :add_issues
  4319. @request.session[:user_id] = 2
  4320. assert_no_difference 'Issue.count' do
  4321. post(
  4322. :create,
  4323. :params => {
  4324. :issue => {
  4325. :project_id => 3,
  4326. :tracker_id => 2,
  4327. :subject => 'Foo'
  4328. }
  4329. }
  4330. )
  4331. assert_response :unprocessable_entity
  4332. end
  4333. end
  4334. def test_create_without_project_id_with_failure_should_not_set_project
  4335. @request.session[:user_id] = 2
  4336. post(
  4337. :create,
  4338. :params => {
  4339. :issue => {
  4340. :project_id => 3,
  4341. :tracker_id => 2,
  4342. :subject => ''
  4343. }
  4344. }
  4345. )
  4346. assert_response :success
  4347. # no project menu
  4348. assert_select '#main-menu a.overview', 0
  4349. end
  4350. def test_post_create_should_send_a_notification
  4351. ActionMailer::Base.deliveries.clear
  4352. @request.session[:user_id] = 2
  4353. with_settings :notified_events => %w(issue_added) do
  4354. assert_difference 'Issue.count' do
  4355. post(
  4356. :create,
  4357. :params => {
  4358. :project_id => 1,
  4359. :issue => {
  4360. :tracker_id => 3,
  4361. :subject => 'This is the test_new issue',
  4362. :description => 'This is the description',
  4363. :priority_id => 5,
  4364. :estimated_hours => '',
  4365. :custom_field_values => {
  4366. '2' => 'Value for field 2'
  4367. }
  4368. }
  4369. }
  4370. )
  4371. end
  4372. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  4373. assert_equal 2, ActionMailer::Base.deliveries.size
  4374. end
  4375. end
  4376. def test_post_create_should_preserve_fields_values_on_validation_failure
  4377. @request.session[:user_id] = 2
  4378. post(
  4379. :create,
  4380. :params => {
  4381. :project_id => 1,
  4382. :issue => {
  4383. :tracker_id => 1,
  4384. :subject => '', # empty subject
  4385. :description => 'This is a description',
  4386. :priority_id => 6,
  4387. :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}
  4388. }
  4389. }
  4390. )
  4391. assert_response :success
  4392. assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
  4393. assert_select 'select[name=?]', 'issue[priority_id]' do
  4394. assert_select 'option[value="6"][selected=selected]', :text => 'High'
  4395. end
  4396. # Custom fields
  4397. assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
  4398. assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
  4399. end
  4400. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
  4401. end
  4402. def test_post_create_with_failure_should_preserve_watchers
  4403. assert !User.find(8).member_of?(Project.find(1))
  4404. @request.session[:user_id] = 2
  4405. post(
  4406. :create,
  4407. :params => {
  4408. :project_id => 1,
  4409. :issue => {
  4410. :tracker_id => 1,
  4411. :watcher_user_ids => ['3', '8']
  4412. }
  4413. }
  4414. )
  4415. assert_response :success
  4416. assert_select 'input[name=?][value="2"]:not(checked)', 'issue[watcher_user_ids][]'
  4417. assert_select 'input[name=?][value="3"][checked=checked]', 'issue[watcher_user_ids][]'
  4418. assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]'
  4419. end
  4420. def test_post_create_with_failure_should_not_dereference_group_watchers
  4421. @request.session[:user_id] = 1
  4422. post(
  4423. :create,
  4424. :params => {
  4425. :project_id => 5,
  4426. :issue => {
  4427. :tracker_id => 1,
  4428. :watcher_user_ids => ['11']
  4429. }
  4430. }
  4431. )
  4432. assert_response :success
  4433. assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]', 0
  4434. assert_select 'input[name=?][value="11"][checked=checked]', 'issue[watcher_user_ids][]', 1
  4435. end
  4436. def test_post_create_should_ignore_non_safe_attributes
  4437. @request.session[:user_id] = 2
  4438. assert_nothing_raised do
  4439. post(
  4440. :create,
  4441. :params => {
  4442. :project_id => 1,
  4443. :issue => {
  4444. :tracker => "A param can not be a Tracker"
  4445. }
  4446. }
  4447. )
  4448. end
  4449. end
  4450. def test_post_create_with_attachment
  4451. set_tmp_attachments_directory
  4452. @request.session[:user_id] = 2
  4453. assert_difference 'Issue.count' do
  4454. assert_difference 'Attachment.count' do
  4455. assert_no_difference 'Journal.count' do
  4456. post(
  4457. :create,
  4458. :params => {
  4459. :project_id => 1,
  4460. :issue => {
  4461. :tracker_id => '1',
  4462. :subject => 'With attachment'
  4463. },
  4464. :attachments => {
  4465. '1' => {
  4466. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4467. 'description' => 'test file'
  4468. }
  4469. }
  4470. }
  4471. )
  4472. end
  4473. end
  4474. end
  4475. issue = Issue.order('id DESC').first
  4476. attachment = Attachment.order('id DESC').first
  4477. assert_equal issue, attachment.container
  4478. assert_equal 2, attachment.author_id
  4479. assert_equal 'testfile.txt', attachment.filename
  4480. assert_equal 'text/plain', attachment.content_type
  4481. assert_equal 'test file', attachment.description
  4482. assert_equal 59, attachment.filesize
  4483. assert File.exist?(attachment.diskfile)
  4484. assert_equal 59, File.size(attachment.diskfile)
  4485. end
  4486. def test_post_create_with_attachment_should_notify_with_attachments
  4487. ActionMailer::Base.deliveries.clear
  4488. set_tmp_attachments_directory
  4489. @request.session[:user_id] = 2
  4490. with_settings :notified_events => %w(issue_added) do
  4491. assert_difference 'Issue.count' do
  4492. post(
  4493. :create,
  4494. :params => {
  4495. :project_id => 1,
  4496. :issue => {
  4497. :tracker_id => '1',
  4498. :subject => 'With attachment'
  4499. },
  4500. :attachments => {
  4501. '1' => {
  4502. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4503. 'description' => 'test file'
  4504. }
  4505. }
  4506. }
  4507. )
  4508. end
  4509. end
  4510. assert_not_nil ActionMailer::Base.deliveries.last
  4511. assert_select_email do
  4512. assert_select 'a[href^=?]', 'http://localhost:3000/attachments/download', 'testfile.txt'
  4513. end
  4514. end
  4515. def test_post_create_with_failure_should_save_attachments
  4516. set_tmp_attachments_directory
  4517. @request.session[:user_id] = 2
  4518. assert_no_difference 'Issue.count' do
  4519. assert_difference 'Attachment.count' do
  4520. post(
  4521. :create,
  4522. :params => {
  4523. :project_id => 1,
  4524. :issue => {
  4525. :tracker_id => '1',
  4526. :subject => ''
  4527. },
  4528. :attachments => {
  4529. '1' => {
  4530. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4531. 'description' => 'test file'
  4532. }
  4533. }
  4534. }
  4535. )
  4536. assert_response :success
  4537. end
  4538. end
  4539. attachment = Attachment.order('id DESC').first
  4540. assert_equal 'testfile.txt', attachment.filename
  4541. assert File.exist?(attachment.diskfile)
  4542. assert_nil attachment.container
  4543. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  4544. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  4545. end
  4546. def test_post_create_with_failure_should_keep_saved_attachments
  4547. set_tmp_attachments_directory
  4548. attachment =
  4549. Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"),
  4550. :author_id => 2)
  4551. @request.session[:user_id] = 2
  4552. assert_no_difference 'Issue.count' do
  4553. assert_no_difference 'Attachment.count' do
  4554. post(
  4555. :create,
  4556. :params => {
  4557. :project_id => 1,
  4558. :issue => {
  4559. :tracker_id => '1',
  4560. :subject => ''
  4561. },
  4562. :attachments => {
  4563. 'p0' => {
  4564. 'token' => attachment.token
  4565. }
  4566. }
  4567. }
  4568. )
  4569. assert_response :success
  4570. end
  4571. end
  4572. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  4573. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  4574. end
  4575. def test_post_create_should_attach_saved_attachments
  4576. set_tmp_attachments_directory
  4577. attachment =
  4578. Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"),
  4579. :author_id => 2)
  4580. @request.session[:user_id] = 2
  4581. assert_difference 'Issue.count' do
  4582. assert_no_difference 'Attachment.count' do
  4583. post(
  4584. :create,
  4585. :params => {
  4586. :project_id => 1,
  4587. :issue => {
  4588. :tracker_id => '1',
  4589. :subject => 'Saved attachments'
  4590. },
  4591. :attachments => {
  4592. 'p0' => {
  4593. 'token' => attachment.token
  4594. }
  4595. }
  4596. }
  4597. )
  4598. assert_response :found
  4599. end
  4600. end
  4601. issue = Issue.order('id DESC').first
  4602. assert_equal 1, issue.attachments.count
  4603. attachment.reload
  4604. assert_equal issue, attachment.container
  4605. end
  4606. def setup_without_workflow_privilege
  4607. WorkflowTransition.where(["role_id = ?", Role.anonymous.id]).delete_all
  4608. Role.anonymous.add_permission! :add_issues, :add_issue_notes
  4609. end
  4610. private :setup_without_workflow_privilege
  4611. test "without workflow privilege #new should propose default status only" do
  4612. setup_without_workflow_privilege
  4613. get(:new, :params => {:project_id => 1})
  4614. assert_response :success
  4615. assert_select 'select[name=?]', 'issue[status_id]' do
  4616. assert_select 'option', 1
  4617. assert_select 'option[value=?][selected=selected]', '1'
  4618. end
  4619. end
  4620. test "without workflow privilege #create should accept default status" do
  4621. setup_without_workflow_privilege
  4622. assert_difference 'Issue.count' do
  4623. post(
  4624. :create,
  4625. :params => {
  4626. :project_id => 1,
  4627. :issue => {
  4628. :tracker_id => 1,
  4629. :subject => 'This is an issue',
  4630. :status_id => 1
  4631. }
  4632. }
  4633. )
  4634. end
  4635. issue = Issue.order('id').last
  4636. assert_not_nil issue.default_status
  4637. assert_equal issue.default_status, issue.status
  4638. end
  4639. test "without workflow privilege #create should ignore unauthorized status" do
  4640. setup_without_workflow_privilege
  4641. assert_difference 'Issue.count' do
  4642. post(
  4643. :create,
  4644. :params => {
  4645. :project_id => 1,
  4646. :issue => {
  4647. :tracker_id => 1,
  4648. :subject => 'This is an issue',
  4649. :status_id => 3
  4650. }
  4651. }
  4652. )
  4653. end
  4654. issue = Issue.order('id').last
  4655. assert_not_nil issue.default_status
  4656. assert_equal issue.default_status, issue.status
  4657. end
  4658. test "without workflow privilege #update should ignore status change" do
  4659. setup_without_workflow_privilege
  4660. assert_difference 'Journal.count' do
  4661. put(
  4662. :update,
  4663. :params => {
  4664. :id => 1,
  4665. :issue => {
  4666. :status_id => 3,
  4667. :notes => 'just trying'
  4668. }
  4669. }
  4670. )
  4671. end
  4672. assert_equal 1, Issue.find(1).status_id
  4673. end
  4674. test "without workflow privilege #update ignore attributes changes" do
  4675. setup_without_workflow_privilege
  4676. assert_difference 'Journal.count' do
  4677. put(
  4678. :update,
  4679. :params => {
  4680. :id => 1,
  4681. :issue => {
  4682. :subject => 'changed',
  4683. :assigned_to_id => 2,
  4684. :notes => 'just trying'
  4685. }
  4686. }
  4687. )
  4688. end
  4689. issue = Issue.find(1)
  4690. assert_equal "Cannot print recipes", issue.subject
  4691. assert_nil issue.assigned_to
  4692. end
  4693. def setup_with_workflow_privilege
  4694. WorkflowTransition.where(["role_id = ?", Role.anonymous.id]).delete_all
  4695. WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
  4696. :old_status_id => 1, :new_status_id => 3)
  4697. WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
  4698. :old_status_id => 1, :new_status_id => 4)
  4699. Role.anonymous.add_permission! :add_issues, :add_issue_notes
  4700. end
  4701. private :setup_with_workflow_privilege
  4702. def setup_with_workflow_privilege_and_edit_issues_permission
  4703. setup_with_workflow_privilege
  4704. Role.anonymous.add_permission! :add_issues, :edit_issues
  4705. end
  4706. private :setup_with_workflow_privilege_and_edit_issues_permission
  4707. test "with workflow privilege and :edit_issues permission should accept authorized status" do
  4708. setup_with_workflow_privilege_and_edit_issues_permission
  4709. assert_difference 'Journal.count' do
  4710. put(
  4711. :update,
  4712. :params => {
  4713. :id => 1,
  4714. :issue => {
  4715. :status_id => 3,
  4716. :notes => 'just trying'
  4717. }
  4718. }
  4719. )
  4720. end
  4721. assert_equal 3, Issue.find(1).status_id
  4722. end
  4723. test "with workflow privilege and :edit_issues permission should ignore unauthorized status" do
  4724. setup_with_workflow_privilege_and_edit_issues_permission
  4725. assert_difference 'Journal.count' do
  4726. put(
  4727. :update,
  4728. :params => {
  4729. :id => 1,
  4730. :issue => {
  4731. :status_id => 2,
  4732. :notes => 'just trying'
  4733. }
  4734. }
  4735. )
  4736. end
  4737. assert_equal 1, Issue.find(1).status_id
  4738. end
  4739. test "with workflow privilege and :edit_issues permission should accept authorized attributes changes" do
  4740. setup_with_workflow_privilege_and_edit_issues_permission
  4741. assert_difference 'Journal.count' do
  4742. put(
  4743. :update,
  4744. :params => {
  4745. :id => 1,
  4746. :issue => {
  4747. :subject => 'changed',
  4748. :assigned_to_id => 2,
  4749. :notes => 'just trying'
  4750. }
  4751. }
  4752. )
  4753. end
  4754. issue = Issue.find(1)
  4755. assert_equal "changed", issue.subject
  4756. assert_equal 2, issue.assigned_to_id
  4757. end
  4758. def test_new_as_copy
  4759. orig = Issue.find(1)
  4760. @request.session[:user_id] = 2
  4761. get(
  4762. :new,
  4763. :params => {
  4764. :project_id => 1,
  4765. :copy_from => orig.id
  4766. }
  4767. )
  4768. assert_response :success
  4769. assert_select 'form[id=issue-form][action="/projects/ecookbook/issues"]' do
  4770. assert_select 'select[name=?]', 'issue[project_id]' do
  4771. assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook'
  4772. assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore'
  4773. end
  4774. assert_select 'input[name=?][value=?]', 'issue[subject]', orig.subject
  4775. assert_select 'input[name=copy_from][value="1"]'
  4776. end
  4777. end
  4778. def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
  4779. user = setup_user_with_copy_but_not_add_permission
  4780. @request.session[:user_id] = user.id
  4781. get(
  4782. :new,
  4783. :params => {
  4784. :project_id => 1,
  4785. :copy_from => 1
  4786. }
  4787. )
  4788. assert_response :success
  4789. assert_select 'select[name=?]', 'issue[project_id]' do
  4790. assert_select 'option[value="1"]', 0
  4791. assert_select 'option[value="2"]', :text => 'OnlineStore'
  4792. end
  4793. end
  4794. def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
  4795. @request.session[:user_id] = 2
  4796. issue = Issue.find(3)
  4797. assert issue.attachments.count > 0
  4798. get(
  4799. :new,
  4800. :params => {
  4801. :project_id => 1,
  4802. :copy_from => 3
  4803. }
  4804. )
  4805. assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value="1"]'
  4806. end
  4807. def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
  4808. @request.session[:user_id] = 2
  4809. issue = Issue.find(3)
  4810. issue.attachments.delete_all
  4811. get(
  4812. :new,
  4813. :params => {
  4814. :project_id => 1,
  4815. :copy_from => 3
  4816. }
  4817. )
  4818. assert_select 'input[name=copy_attachments]', 0
  4819. end
  4820. def test_new_as_copy_should_preserve_parent_id
  4821. @request.session[:user_id] = 2
  4822. issue = Issue.generate!(:parent_issue_id => 2)
  4823. get(
  4824. :new,
  4825. :params => {
  4826. :project_id => 1,
  4827. :copy_from => issue.id
  4828. }
  4829. )
  4830. assert_select 'input[name=?][value="2"]', 'issue[parent_issue_id]'
  4831. end
  4832. def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
  4833. @request.session[:user_id] = 2
  4834. issue = Issue.generate_with_descendants!
  4835. get(
  4836. :new,
  4837. :params => {
  4838. :project_id => 1,
  4839. :copy_from => issue.id
  4840. }
  4841. )
  4842. assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value="1"]'
  4843. end
  4844. def test_new_as_copy_should_preserve_watchers
  4845. @request.session[:user_id] = 2
  4846. issue = Issue.find(1)
  4847. user = User.generate!
  4848. Watcher.create!(:watchable => issue, :user => user)
  4849. Watcher.create!(:watchable => issue, :user => Group.find(10))
  4850. get(
  4851. :new,
  4852. :params => {
  4853. :project_id => 1,
  4854. :copy_from => 1
  4855. }
  4856. )
  4857. assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 2
  4858. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4859. 'issue[watcher_user_ids][]', user.id.to_s
  4860. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4861. 'issue[watcher_user_ids][]', '10'
  4862. assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1
  4863. end
  4864. def test_new_as_copy_should_not_propose_locked_watchers
  4865. @request.session[:user_id] = 2
  4866. issue = Issue.find(1)
  4867. user = User.generate!
  4868. user2 = User.generate!
  4869. Watcher.create!(:watchable => issue, :user => user)
  4870. Watcher.create!(:watchable => issue, :user => user2)
  4871. user2.status = User::STATUS_LOCKED
  4872. user2.save!
  4873. get(
  4874. :new,
  4875. :params => {
  4876. :project_id => 1,
  4877. :copy_from => 1
  4878. }
  4879. )
  4880. assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 1
  4881. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4882. 'issue[watcher_user_ids][]', user.id.to_s
  4883. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4884. 'issue[watcher_user_ids][]', user2.id.to_s, 0
  4885. assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1
  4886. end
  4887. def test_new_as_copy_with_invalid_issue_should_respond_with_404
  4888. @request.session[:user_id] = 2
  4889. get(
  4890. :new,
  4891. :params => {
  4892. :project_id => 1,
  4893. :copy_from => 99999
  4894. }
  4895. )
  4896. assert_response :not_found
  4897. end
  4898. def test_create_as_copy_on_different_project
  4899. @request.session[:user_id] = 2
  4900. assert_difference 'Issue.count' do
  4901. post(
  4902. :create,
  4903. :params => {
  4904. :project_id => 1,
  4905. :copy_from => 1,
  4906. :issue => {
  4907. :project_id => '2',
  4908. :tracker_id => '3',
  4909. :status_id => '1',
  4910. :subject => 'Copy'
  4911. }
  4912. }
  4913. )
  4914. end
  4915. issue = Issue.order('id DESC').first
  4916. assert_redirected_to "/issues/#{issue.id}"
  4917. assert_equal 2, issue.project_id
  4918. assert_equal 3, issue.tracker_id
  4919. assert_equal 'Copy', issue.subject
  4920. end
  4921. def test_create_as_copy_should_allow_status_to_be_set_to_default
  4922. copied = Issue.generate! :status_id => 2
  4923. assert_equal 2, copied.reload.status_id
  4924. @request.session[:user_id] = 2
  4925. assert_difference 'Issue.count' do
  4926. post(
  4927. :create,
  4928. :params => {
  4929. :project_id => 1,
  4930. :copy_from => copied.id,
  4931. :issue => {
  4932. :project_id => '1',
  4933. :tracker_id => '1',
  4934. :status_id => '1'
  4935. },
  4936. :was_default_status => '1'
  4937. }
  4938. )
  4939. end
  4940. issue = Issue.order('id DESC').first
  4941. assert_equal 1, issue.status_id
  4942. end
  4943. def test_create_as_copy_should_fail_without_add_issue_permission_on_original_tracker
  4944. role = Role.find(2)
  4945. role.set_permission_trackers :add_issues, [1, 3]
  4946. role.save!
  4947. Role.non_member.remove_permission! :add_issues
  4948. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  4949. @request.session[:user_id] = 3
  4950. assert_no_difference 'Issue.count' do
  4951. post(
  4952. :create,
  4953. :params => {
  4954. :project_id => 1,
  4955. :copy_from => issue.id,
  4956. :issue => {
  4957. :project_id => '1'
  4958. }
  4959. }
  4960. )
  4961. end
  4962. assert_select_error 'Tracker is invalid'
  4963. end
  4964. def test_create_as_copy_should_copy_attachments
  4965. @request.session[:user_id] = 2
  4966. issue = Issue.find(3)
  4967. count = issue.attachments.count
  4968. assert count > 0
  4969. assert_difference 'Issue.count' do
  4970. assert_difference 'Attachment.count', count do
  4971. post(
  4972. :create,
  4973. :params => {
  4974. :project_id => 1,
  4975. :copy_from => 3,
  4976. :issue => {
  4977. :project_id => '1',
  4978. :tracker_id => '3',
  4979. :status_id => '1',
  4980. :subject => 'Copy with attachments'
  4981. },
  4982. :copy_attachments => '1'
  4983. }
  4984. )
  4985. end
  4986. end
  4987. copy = Issue.order('id DESC').first
  4988. assert_equal count, copy.attachments.count
  4989. assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
  4990. end
  4991. def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
  4992. @request.session[:user_id] = 2
  4993. issue = Issue.find(3)
  4994. count = issue.attachments.count
  4995. assert count > 0
  4996. assert_difference 'Issue.count' do
  4997. assert_no_difference 'Attachment.count' do
  4998. post(
  4999. :create,
  5000. :params => {
  5001. :project_id => 1,
  5002. :copy_from => 3,
  5003. :issue => {
  5004. :project_id => '1',
  5005. :tracker_id => '3',
  5006. :status_id => '1',
  5007. :subject => 'Copy with attachments'
  5008. }
  5009. }
  5010. )
  5011. end
  5012. end
  5013. copy = Issue.order('id DESC').first
  5014. assert_equal 0, copy.attachments.count
  5015. end
  5016. def test_create_as_copy_with_attachments_should_also_add_new_files
  5017. set_tmp_attachments_directory
  5018. @request.session[:user_id] = 2
  5019. issue = Issue.find(3)
  5020. count = issue.attachments.count
  5021. assert count > 0
  5022. assert_difference 'Issue.count' do
  5023. assert_difference 'Attachment.count', count + 1 do
  5024. post(
  5025. :create,
  5026. :params => {
  5027. :project_id => 1,
  5028. :copy_from => 3,
  5029. :issue => {
  5030. :project_id => '1',
  5031. :tracker_id => '3',
  5032. :status_id => '1',
  5033. :subject => 'Copy with attachments'
  5034. },
  5035. :copy_attachments => '1',
  5036. :attachments => {
  5037. '1' => {
  5038. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  5039. 'description' => 'test file'
  5040. }
  5041. }
  5042. }
  5043. )
  5044. end
  5045. end
  5046. copy = Issue.order('id DESC').first
  5047. assert_equal count + 1, copy.attachments.count
  5048. end
  5049. def test_create_as_copy_should_add_relation_with_copied_issue
  5050. @request.session[:user_id] = 2
  5051. assert_difference 'Issue.count' do
  5052. assert_difference 'IssueRelation.count' do
  5053. post(
  5054. :create,
  5055. :params => {
  5056. :project_id => 1,
  5057. :copy_from => 1,
  5058. :link_copy => '1',
  5059. :issue => {
  5060. :project_id => '1',
  5061. :tracker_id => '3',
  5062. :status_id => '1',
  5063. :subject => 'Copy'
  5064. }
  5065. }
  5066. )
  5067. end
  5068. end
  5069. copy = Issue.order('id DESC').first
  5070. assert_equal 1, copy.relations.size
  5071. end
  5072. def test_create_as_copy_should_allow_not_to_add_relation_with_copied_issue
  5073. @request.session[:user_id] = 2
  5074. assert_difference 'Issue.count' do
  5075. assert_no_difference 'IssueRelation.count' do
  5076. post(
  5077. :create,
  5078. :params => {
  5079. :project_id => 1,
  5080. :copy_from => 1,
  5081. :issue => {
  5082. :subject => 'Copy'
  5083. }
  5084. }
  5085. )
  5086. end
  5087. end
  5088. end
  5089. def test_create_as_copy_should_always_add_relation_with_copied_issue_by_setting
  5090. with_settings :link_copied_issue => 'yes' do
  5091. @request.session[:user_id] = 2
  5092. assert_difference 'Issue.count' do
  5093. assert_difference 'IssueRelation.count' do
  5094. post(
  5095. :create,
  5096. :params => {
  5097. :project_id => 1,
  5098. :copy_from => 1,
  5099. :issue => {
  5100. :subject => 'Copy'
  5101. }
  5102. }
  5103. )
  5104. end
  5105. end
  5106. end
  5107. end
  5108. def test_create_as_copy_should_never_add_relation_with_copied_issue_by_setting
  5109. with_settings :link_copied_issue => 'no' do
  5110. @request.session[:user_id] = 2
  5111. assert_difference 'Issue.count' do
  5112. assert_no_difference 'IssueRelation.count' do
  5113. post(
  5114. :create,
  5115. :params => {
  5116. :project_id => 1,
  5117. :copy_from => 1,
  5118. :link_copy => '1',
  5119. :issue => {
  5120. :subject => 'Copy'
  5121. }
  5122. }
  5123. )
  5124. end
  5125. end
  5126. end
  5127. end
  5128. def test_create_as_copy_should_copy_subtasks
  5129. @request.session[:user_id] = 2
  5130. issue = Issue.generate_with_descendants!
  5131. count = issue.descendants.count
  5132. assert_difference 'Issue.count', count + 1 do
  5133. post(
  5134. :create,
  5135. :params => {
  5136. :project_id => 1,
  5137. :copy_from => issue.id,
  5138. :issue => {
  5139. :project_id => '1',
  5140. :tracker_id => '3',
  5141. :status_id => '1',
  5142. :subject => 'Copy with subtasks'
  5143. },
  5144. :copy_subtasks => '1'
  5145. }
  5146. )
  5147. end
  5148. copy = Issue.where(:parent_id => nil).order('id DESC').first
  5149. assert_equal count, copy.descendants.count
  5150. assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
  5151. end
  5152. def test_create_as_copy_to_a_different_project_should_copy_subtask_custom_fields
  5153. issue = Issue.generate! {|i| i.custom_field_values = {'2' => 'Foo'}}
  5154. child = Issue.generate!(:parent_issue_id => issue.id) {|i| i.custom_field_values = {'2' => 'Bar'}}
  5155. @request.session[:user_id] = 1
  5156. assert_difference 'Issue.count', 2 do
  5157. post(
  5158. :create,
  5159. :params => {
  5160. :project_id => 'ecookbook',
  5161. :copy_from => issue.id,
  5162. :issue => {
  5163. :project_id => '2',
  5164. :tracker_id => 1,
  5165. :status_id => '1',
  5166. :subject => 'Copy with subtasks',
  5167. :custom_field_values => {
  5168. '2' => 'Foo'
  5169. }
  5170. },
  5171. :copy_subtasks => '1'
  5172. }
  5173. )
  5174. end
  5175. child_copy, issue_copy = Issue.order(:id => :desc).limit(2).to_a
  5176. assert_equal 2, issue_copy.project_id
  5177. assert_equal 'Foo', issue_copy.custom_field_value(2)
  5178. assert_equal 'Bar', child_copy.custom_field_value(2)
  5179. end
  5180. def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
  5181. @request.session[:user_id] = 2
  5182. issue = Issue.generate_with_descendants!
  5183. assert_difference 'Issue.count', 1 do
  5184. post(
  5185. :create,
  5186. :params => {
  5187. :project_id => 1,
  5188. :copy_from => 3,
  5189. :issue => {
  5190. :project_id => '1',
  5191. :tracker_id => '3',
  5192. :status_id => '1',
  5193. :subject => 'Copy with subtasks'
  5194. }
  5195. }
  5196. )
  5197. end
  5198. copy = Issue.where(:parent_id => nil).order('id DESC').first
  5199. assert_equal 0, copy.descendants.count
  5200. end
  5201. def test_create_as_copy_with_failure
  5202. @request.session[:user_id] = 2
  5203. post(
  5204. :create,
  5205. :params => {
  5206. :project_id => 1,
  5207. :copy_from => 1,
  5208. :issue => {
  5209. :project_id => '2',
  5210. :tracker_id => '3',
  5211. :status_id => '1',
  5212. :subject => ''
  5213. }
  5214. }
  5215. )
  5216. assert_response :success
  5217. assert_select 'form#issue-form[action="/projects/ecookbook/issues"]' do
  5218. assert_select 'select[name=?]', 'issue[project_id]' do
  5219. assert_select 'option[value="1"]:not([selected])', :text => 'eCookbook'
  5220. assert_select 'option[value="2"][selected=selected]', :text => 'OnlineStore'
  5221. end
  5222. assert_select 'input[name=copy_from][value="1"]'
  5223. end
  5224. end
  5225. def test_create_as_copy_on_project_without_permission_should_ignore_target_project
  5226. @request.session[:user_id] = 2
  5227. assert !User.find(2).member_of?(Project.find(4))
  5228. assert_difference 'Issue.count' do
  5229. post(
  5230. :create,
  5231. :params => {
  5232. :project_id => 1,
  5233. :copy_from => 1,
  5234. :issue => {
  5235. :project_id => '4',
  5236. :tracker_id => '3',
  5237. :status_id => '1',
  5238. :subject => 'Copy'
  5239. }
  5240. }
  5241. )
  5242. end
  5243. issue = Issue.order('id DESC').first
  5244. assert_equal 1, issue.project_id
  5245. end
  5246. def test_create_as_copy_with_watcher_user_ids_should_copy_watchers
  5247. @request.session[:user_id] = 2
  5248. copied = Issue.generate!
  5249. copied.add_watcher User.find(2)
  5250. copied.add_watcher User.find(3)
  5251. assert_difference 'Issue.count' do
  5252. post(
  5253. :create,
  5254. :params => {
  5255. :project_id => 1,
  5256. :copy_from => copied.id,
  5257. :issue => {
  5258. :subject => 'Copy cleared watchers',
  5259. :watcher_user_ids => ['', '3', '10']
  5260. }
  5261. }
  5262. )
  5263. end
  5264. issue = Issue.order('id DESC').first
  5265. assert_equal [3, 10], issue.watcher_user_ids.sort
  5266. end
  5267. def test_create_as_copy_without_watcher_user_ids_should_not_copy_watchers
  5268. @request.session[:user_id] = 2
  5269. copied = Issue.generate!
  5270. copied.add_watcher User.find(2)
  5271. copied.add_watcher User.find(3)
  5272. assert_difference 'Issue.count' do
  5273. post(
  5274. :create,
  5275. :params => {
  5276. :project_id => 1,
  5277. :copy_from => copied.id,
  5278. :issue => {
  5279. :subject => 'Copy cleared watchers',
  5280. :watcher_user_ids => ['']
  5281. }
  5282. }
  5283. )
  5284. end
  5285. issue = Issue.order('id DESC').first
  5286. assert_equal [], issue.watcher_user_ids
  5287. end
  5288. def test_get_edit
  5289. @request.session[:user_id] = 2
  5290. get(:edit, :params => {:id => 1})
  5291. assert_response :success
  5292. assert_select 'select[name=?]', 'issue[project_id]'
  5293. # Be sure we don't display inactive IssuePriorities
  5294. assert_not IssuePriority.find(15).active?
  5295. assert_select 'select[name=?]', 'issue[priority_id]' do
  5296. assert_select 'option[value="15"]', 0
  5297. end
  5298. assert_select 'span.icon-warning', 0
  5299. end
  5300. def test_edit_should_hide_project_if_user_is_not_allowed_to_change_project
  5301. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5302. :field_name => 'project_id', :rule => 'readonly')
  5303. @request.session[:user_id] = 2
  5304. get(:edit, :params => {:id => 1})
  5305. assert_response :success
  5306. assert_select 'select[name=?]', 'issue[project_id]', 0
  5307. end
  5308. def test_new_should_hide_project_if_user_is_not_allowed_to_change_project_in_hierarchy_projects
  5309. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5310. :field_name => 'project_id', :rule => 'readonly')
  5311. @request.session[:user_id] = 2
  5312. get(:new, :params => { :tracker_id => 1, :project_id => 1 })
  5313. assert_response :success
  5314. assert_select 'select[name=?]', 'issue[project_id]', 0
  5315. end
  5316. def test_new_should_show_project_if_user_is_not_allowed_to_change_project_global_new_issue
  5317. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5318. :field_name => 'project_id', :rule => 'readonly')
  5319. @request.session[:user_id] = 2
  5320. get(:new, :params => { :tracker_id => 1})
  5321. assert_response :success
  5322. assert_select 'select[name=?]', 'issue[project_id]'
  5323. end
  5324. def test_edit_should_not_hide_project_when_user_changes_the_project_even_if_project_is_readonly_on_target_project
  5325. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5326. :field_name => 'project_id', :rule => 'readonly')
  5327. issue = Issue.generate!(:project_id => 2)
  5328. @request.session[:user_id] = 2
  5329. get(
  5330. :edit,
  5331. :params => {
  5332. :id => issue.id,
  5333. :issue => {
  5334. :project_id => 1
  5335. }
  5336. }
  5337. )
  5338. assert_response :success
  5339. assert_select 'select[name=?]', 'issue[project_id]'
  5340. end
  5341. def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
  5342. @request.session[:user_id] = 2
  5343. Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
  5344. get(:edit, :params => {:id => 1})
  5345. assert_select 'input[name=?]', 'time_entry[hours]'
  5346. end
  5347. def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
  5348. @request.session[:user_id] = 2
  5349. Role.find_by_name('Manager').remove_permission! :log_time
  5350. get(:edit, :params => {:id => 1})
  5351. assert_select 'input[name=?]', 'time_entry[hours]', 0
  5352. end
  5353. def test_get_edit_with_params
  5354. @request.session[:user_id] = 2
  5355. get(
  5356. :edit,
  5357. :params => {
  5358. :id => 1,
  5359. :issue => {
  5360. :status_id => 5,
  5361. :priority_id => 7
  5362. },
  5363. :time_entry => {
  5364. :hours => '2:30',
  5365. :comments => 'test_get_edit_with_params',
  5366. :activity_id => 10
  5367. }
  5368. }
  5369. )
  5370. assert_response :success
  5371. assert_select 'select[name=?]', 'issue[status_id]' do
  5372. assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
  5373. end
  5374. assert_select 'select[name=?]', 'issue[priority_id]' do
  5375. assert_select 'option[value="7"][selected=selected]', :text => 'Urgent'
  5376. end
  5377. assert_select 'input[name=?][value="2:30"]', 'time_entry[hours]'
  5378. assert_select 'select[name=?]', 'time_entry[activity_id]' do
  5379. assert_select 'option[value="10"][selected=selected]', :text => 'Development'
  5380. end
  5381. assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
  5382. end
  5383. def test_get_edit_with_multi_custom_field
  5384. field = CustomField.find(1)
  5385. field.update_attribute :multiple, true
  5386. issue = Issue.find(1)
  5387. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  5388. issue.save!
  5389. @request.session[:user_id] = 2
  5390. get(:edit, :params => {:id => 1})
  5391. assert_response :success
  5392. assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
  5393. assert_select 'option', 3
  5394. assert_select 'option[value=MySQL][selected=selected]'
  5395. assert_select 'option[value=Oracle][selected=selected]'
  5396. assert_select 'option[value=PostgreSQL]:not([selected])'
  5397. end
  5398. end
  5399. def test_get_edit_with_me_assigned_to_id
  5400. @request.session[:user_id] = 2
  5401. get(
  5402. :edit,
  5403. :params => {
  5404. :id => 1,
  5405. :issue => {:assigned_to_id => 'me'}
  5406. }
  5407. )
  5408. assert_response :success
  5409. assert_select 'select[name=?]', 'issue[assigned_to_id]' do
  5410. assert_select 'option[value="2"][selected=selected]'
  5411. end
  5412. end
  5413. def test_get_edit_for_issue_with_transition_warning_should_show_the_warning
  5414. @request.session[:user_id] = 2
  5415. get(
  5416. :edit,
  5417. :params => {
  5418. :id => 9,
  5419. }
  5420. )
  5421. assert_response :success
  5422. reason = l(:notice_issue_not_closable_by_blocking_issue)
  5423. assert_select 'span.icon-warning[title=?]', reason, :text => reason
  5424. end
  5425. def test_get_edit_should_display_visible_spent_time_custom_field
  5426. @request.session[:user_id] = 2
  5427. get(
  5428. :edit,
  5429. :params => {
  5430. :id => 13,
  5431. }
  5432. )
  5433. assert_response :success
  5434. assert_select '#issue-form select.cf_10', 1
  5435. end
  5436. def test_get_edit_should_not_display_spent_time_custom_field_not_visible
  5437. cf = TimeEntryCustomField.find(10)
  5438. cf.visible = false
  5439. cf.role_ids = [1]
  5440. cf.save!
  5441. @request.session[:user_id] = 2
  5442. get(
  5443. :edit,
  5444. :params => {
  5445. :id => 13,
  5446. }
  5447. )
  5448. assert_response :success
  5449. assert_select '#issue-form select.cf_10', 0
  5450. end
  5451. def test_update_form_for_existing_issue
  5452. @request.session[:user_id] = 2
  5453. patch(
  5454. :edit,
  5455. :params => {
  5456. :id => 1,
  5457. :issue => {
  5458. :tracker_id => 2,
  5459. :subject => 'This is the test_new issue',
  5460. :description => 'This is the description',
  5461. :priority_id => 5
  5462. }
  5463. },
  5464. :xhr => true
  5465. )
  5466. assert_response :success
  5467. assert_equal 'text/javascript', response.media_type
  5468. assert_include 'This is the test_new issue', response.body
  5469. end
  5470. def test_update_form_for_existing_issue_should_keep_issue_author
  5471. @request.session[:user_id] = 3
  5472. patch(
  5473. :edit,
  5474. :params => {
  5475. :id => 1,
  5476. :issue => {
  5477. :subject => 'Changed'
  5478. }
  5479. }
  5480. )
  5481. assert_response :success
  5482. assert_equal User.find(2), Issue.find(1).author
  5483. end
  5484. def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
  5485. @request.session[:user_id] = 2
  5486. WorkflowTransition.delete_all
  5487. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
  5488. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
  5489. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
  5490. patch(
  5491. :edit,
  5492. :params => {
  5493. :id => 2,
  5494. :issue => {
  5495. :tracker_id => 2,
  5496. :status_id => 5,
  5497. :subject => 'This is an issue'
  5498. }
  5499. }
  5500. )
  5501. assert_select 'select[name=?]', 'issue[status_id]' do
  5502. assert_select 'option[value="1"]'
  5503. assert_select 'option[value="2"]'
  5504. assert_select 'option[value="5"][selected=selected]'
  5505. assert_select 'option', 3
  5506. end
  5507. end
  5508. def test_update_form_for_existing_issue_with_project_change
  5509. @request.session[:user_id] = 2
  5510. patch(
  5511. :edit,
  5512. :params => {
  5513. :id => 1,
  5514. :issue => {
  5515. :project_id => 2,
  5516. :tracker_id => 2,
  5517. :subject => 'This is the test_new issue',
  5518. :description => 'This is the description',
  5519. :priority_id => 5
  5520. }
  5521. }
  5522. )
  5523. assert_response :success
  5524. assert_select 'select[name=?]', 'issue[project_id]' do
  5525. assert_select 'option[value="2"][selected=selected]'
  5526. end
  5527. assert_select 'select[name=?]', 'issue[tracker_id]' do
  5528. assert_select 'option[value="2"][selected=selected]'
  5529. end
  5530. assert_select 'input[name=?][value=?]', 'issue[subject]', 'This is the test_new issue'
  5531. end
  5532. def test_update_form_should_keep_category_with_same_when_changing_project
  5533. source = Project.generate!
  5534. target = Project.generate!
  5535. source_category = IssueCategory.create!(:name => 'Foo', :project => source)
  5536. target_category = IssueCategory.create!(:name => 'Foo', :project => target)
  5537. issue = Issue.generate!(:project => source, :category => source_category)
  5538. @request.session[:user_id] = 1
  5539. patch(
  5540. :edit,
  5541. :params => {
  5542. :id => issue.id,
  5543. :issue => {
  5544. :project_id => target.id,
  5545. :category_id => source_category.id
  5546. }
  5547. }
  5548. )
  5549. assert_response :success
  5550. assert_select 'select[name=?]', 'issue[category_id]' do
  5551. assert_select 'option[value=?][selected=selected]', target_category.id.to_s
  5552. end
  5553. end
  5554. def test_update_form_should_propose_default_status_for_existing_issue
  5555. @request.session[:user_id] = 2
  5556. WorkflowTransition.delete_all
  5557. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
  5558. patch(:edit, :params => {:id => 2})
  5559. assert_response :success
  5560. assert_select 'select[name=?]', 'issue[status_id]' do
  5561. assert_select 'option[value="2"]'
  5562. assert_select 'option[value="3"]'
  5563. assert_select 'option', 2
  5564. end
  5565. end
  5566. def test_put_update_without_custom_fields_param
  5567. @request.session[:user_id] = 2
  5568. issue = Issue.find(1)
  5569. assert_equal '125', issue.custom_value_for(2).value
  5570. assert_difference('Journal.count') do
  5571. assert_difference('JournalDetail.count') do
  5572. put(
  5573. :update,
  5574. :params => {
  5575. :id => 1,
  5576. :issue => {
  5577. :subject => 'New subject'
  5578. }
  5579. }
  5580. )
  5581. end
  5582. end
  5583. assert_redirected_to :action => 'show', :id => '1'
  5584. issue.reload
  5585. assert_equal 'New subject', issue.subject
  5586. # Make sure custom fields were not cleared
  5587. assert_equal '125', issue.custom_value_for(2).value
  5588. end
  5589. def test_put_update_with_project_change
  5590. @request.session[:user_id] = 2
  5591. ActionMailer::Base.deliveries.clear
  5592. with_settings :notified_events => %w(issue_updated) do
  5593. assert_difference('Journal.count') do
  5594. assert_difference('JournalDetail.count', 3) do
  5595. put(
  5596. :update,
  5597. :params => {
  5598. :id => 1,
  5599. :issue => {
  5600. :project_id => '2',
  5601. :tracker_id => '1', # no change
  5602. :priority_id => '6',
  5603. :category_id => '3'
  5604. }
  5605. }
  5606. )
  5607. end
  5608. end
  5609. end
  5610. assert_redirected_to :action => 'show', :id => '1'
  5611. issue = Issue.find(1)
  5612. assert_equal 2, issue.project_id
  5613. assert_equal 1, issue.tracker_id
  5614. assert_equal 6, issue.priority_id
  5615. assert_equal 3, issue.category_id
  5616. mail = ActionMailer::Base.deliveries.last
  5617. assert_not_nil mail
  5618. assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
  5619. assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
  5620. end
  5621. def test_put_update_trying_to_move_issue_to_project_without_tracker_should_not_error
  5622. target = Project.generate!(:tracker_ids => [])
  5623. assert target.trackers.empty?
  5624. issue = Issue.generate!
  5625. @request.session[:user_id] = 1
  5626. put(
  5627. :update,
  5628. :params => {
  5629. :id => issue.id,
  5630. :issue => {
  5631. :project_id => target.id
  5632. }
  5633. }
  5634. )
  5635. assert_response :found
  5636. end
  5637. def test_put_update_with_tracker_change
  5638. @request.session[:user_id] = 2
  5639. ActionMailer::Base.deliveries.clear
  5640. with_settings :notified_events => %w(issue_updated) do
  5641. assert_difference('Journal.count') do
  5642. assert_difference('JournalDetail.count', 3) do
  5643. put(
  5644. :update,
  5645. :params => {
  5646. :id => 1,
  5647. :issue => {
  5648. :project_id => '1',
  5649. :tracker_id => '2',
  5650. :priority_id => '6'
  5651. }
  5652. }
  5653. )
  5654. end
  5655. end
  5656. end
  5657. assert_redirected_to :action => 'show', :id => '1'
  5658. issue = Issue.find(1)
  5659. assert_equal 1, issue.project_id
  5660. assert_equal 2, issue.tracker_id
  5661. assert_equal 6, issue.priority_id
  5662. assert_equal 1, issue.category_id
  5663. mail = ActionMailer::Base.deliveries.last
  5664. assert_not_nil mail
  5665. assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
  5666. assert_mail_body_match "Tracker changed from Bug to Feature request", mail
  5667. end
  5668. def test_put_update_with_custom_field_change
  5669. @request.session[:user_id] = 2
  5670. issue = Issue.find(1)
  5671. assert_equal '125', issue.custom_value_for(2).value
  5672. with_settings :notified_events => %w(issue_updated) do
  5673. assert_difference('Journal.count') do
  5674. assert_difference('JournalDetail.count', 3) do
  5675. put(
  5676. :update,
  5677. :params => {
  5678. :id => 1,
  5679. :issue => {
  5680. :subject => 'Custom field change',
  5681. :priority_id => '6',
  5682. :category_id => '1', # no change
  5683. :custom_field_values => {'2' => 'New custom value'}
  5684. }
  5685. }
  5686. )
  5687. end
  5688. end
  5689. end
  5690. assert_redirected_to :action => 'show', :id => '1'
  5691. issue.reload
  5692. assert_equal 'New custom value', issue.custom_value_for(2).value
  5693. mail = ActionMailer::Base.deliveries.last
  5694. assert_not_nil mail
  5695. assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
  5696. end
  5697. def test_put_update_with_multi_custom_field_change
  5698. field = CustomField.find(1)
  5699. field.update_attribute :multiple, true
  5700. issue = Issue.find(1)
  5701. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  5702. issue.save!
  5703. @request.session[:user_id] = 2
  5704. assert_difference('Journal.count') do
  5705. assert_difference('JournalDetail.count', 3) do
  5706. put(
  5707. :update,
  5708. :params => {
  5709. :id => 1,
  5710. :issue => {
  5711. :subject => 'Custom field change',
  5712. :custom_field_values => {
  5713. '1' => ['', 'Oracle', 'PostgreSQL']
  5714. }
  5715. }
  5716. }
  5717. )
  5718. end
  5719. end
  5720. assert_redirected_to :action => 'show', :id => '1'
  5721. assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
  5722. end
  5723. def test_put_update_with_status_and_assignee_change
  5724. issue = Issue.find(1)
  5725. assert_equal 1, issue.status_id
  5726. @request.session[:user_id] = 2
  5727. with_settings :notified_events => %w(issue_updated) do
  5728. assert_difference('TimeEntry.count', 0) do
  5729. put(
  5730. :update,
  5731. :params => {
  5732. :id => 1,
  5733. :issue => {
  5734. :status_id => 2,
  5735. :assigned_to_id => 3,
  5736. :notes => 'Assigned to dlopper'
  5737. },
  5738. :time_entry => {
  5739. :hours => '',
  5740. :comments => '',
  5741. :activity_id => TimeEntryActivity.first
  5742. }
  5743. }
  5744. )
  5745. end
  5746. end
  5747. assert_redirected_to :action => 'show', :id => '1'
  5748. issue.reload
  5749. assert_equal 2, issue.status_id
  5750. j = Journal.order('id DESC').first
  5751. assert_equal 'Assigned to dlopper', j.notes
  5752. assert_equal 2, j.details.size
  5753. mail = ActionMailer::Base.deliveries.last
  5754. assert_mail_body_match "Status changed from New to Assigned", mail
  5755. # subject should contain the new status
  5756. assert mail.subject.include?("(#{IssueStatus.find(2).name})")
  5757. end
  5758. def test_put_update_with_note_only
  5759. notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
  5760. with_settings :notified_events => %w(issue_updated) do
  5761. # anonymous user
  5762. put(
  5763. :update,
  5764. :params => {
  5765. :id => 1,
  5766. :issue => {
  5767. :notes => notes
  5768. }
  5769. }
  5770. )
  5771. end
  5772. assert_redirected_to :action => 'show', :id => '1'
  5773. j = Journal.order('id DESC').first
  5774. assert_equal notes, j.notes
  5775. assert_equal 0, j.details.size
  5776. assert_equal User.anonymous, j.user
  5777. mail = ActionMailer::Base.deliveries.last
  5778. assert_mail_body_match notes, mail
  5779. end
  5780. def test_put_update_with_private_note_only
  5781. notes = 'Private note'
  5782. @request.session[:user_id] = 2
  5783. assert_difference 'Journal.count' do
  5784. put(
  5785. :update,
  5786. :params => {
  5787. :id => 1,
  5788. :issue => {
  5789. :notes => notes,
  5790. :private_notes => '1'
  5791. }
  5792. }
  5793. )
  5794. assert_redirected_to :action => 'show', :id => '1'
  5795. end
  5796. j = Journal.order('id DESC').first
  5797. assert_equal notes, j.notes
  5798. assert_equal true, j.private_notes
  5799. end
  5800. def test_put_update_with_private_note_and_changes
  5801. notes = 'Private note'
  5802. @request.session[:user_id] = 2
  5803. assert_difference 'Journal.count', 2 do
  5804. put(
  5805. :update,
  5806. :params => {
  5807. :id => 1,
  5808. :issue => {
  5809. :subject => 'New subject',
  5810. :notes => notes,
  5811. :private_notes => '1'
  5812. }
  5813. }
  5814. )
  5815. assert_redirected_to :action => 'show', :id => '1'
  5816. end
  5817. j = Journal.order('id DESC').first
  5818. assert_equal notes, j.notes
  5819. assert_equal true, j.private_notes
  5820. assert_equal 0, j.details.count
  5821. j = Journal.order('id DESC').offset(1).first
  5822. assert_nil j.notes
  5823. assert_equal false, j.private_notes
  5824. assert_equal 1, j.details.count
  5825. end
  5826. def test_put_update_with_note_and_spent_time
  5827. @request.session[:user_id] = 2
  5828. spent_hours_before = Issue.find(1).spent_hours
  5829. assert_difference('TimeEntry.count') do
  5830. put(
  5831. :update,
  5832. :params => {
  5833. :id => 1,
  5834. :issue => {
  5835. :notes => '2.5 hours added'
  5836. },
  5837. :time_entry => {
  5838. :hours => '2.5',
  5839. :comments => 'test_put_update_with_note_and_spent_time',
  5840. :activity_id => TimeEntryActivity.first.id
  5841. }
  5842. }
  5843. )
  5844. end
  5845. assert_redirected_to :action => 'show', :id => '1'
  5846. issue = Issue.find(1)
  5847. j = Journal.order('id DESC').first
  5848. assert_equal '2.5 hours added', j.notes
  5849. assert_equal 0, j.details.size
  5850. t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
  5851. assert_not_nil t
  5852. assert_equal 2.5, t.hours
  5853. assert_equal spent_hours_before + 2.5, issue.spent_hours
  5854. end
  5855. def test_put_update_should_check_add_issue_notes_permission
  5856. role = Role.find(1)
  5857. role.remove_permission! :add_issue_notes
  5858. @request.session[:user_id] = 2
  5859. assert_no_difference 'Journal.count' do
  5860. put(
  5861. :update,
  5862. :params => {
  5863. :id => 1,
  5864. :issue => {
  5865. :notes => 'New note'
  5866. }
  5867. }
  5868. )
  5869. end
  5870. end
  5871. def test_put_update_should_preserve_parent_issue_even_if_not_visible
  5872. parent = Issue.generate!(:project_id => 1, :is_private => true)
  5873. issue = Issue.generate!(:parent_issue_id => parent.id)
  5874. assert !parent.visible?(User.find(3))
  5875. @request.session[:user_id] = 3
  5876. get(:edit, :params => {:id => issue.id})
  5877. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
  5878. put(
  5879. :update,
  5880. :params => {
  5881. :id => issue.id,
  5882. :issue => {
  5883. :subject => 'New subject',
  5884. :parent_issue_id => parent.id.to_s
  5885. }
  5886. }
  5887. )
  5888. assert_response :found
  5889. assert_equal parent, issue.parent
  5890. end
  5891. def test_put_update_with_attachment_only
  5892. set_tmp_attachments_directory
  5893. # Delete all fixtured journals, a race condition can occur causing the wrong
  5894. # journal to get fetched in the next find.
  5895. Journal.delete_all
  5896. JournalDetail.delete_all
  5897. with_settings :notified_events => %w(issue_updated) do
  5898. # anonymous user
  5899. assert_difference 'Attachment.count' do
  5900. put(
  5901. :update,
  5902. :params => {
  5903. :id => 1,
  5904. :issue => {
  5905. :notes => ''
  5906. },
  5907. :attachments => {
  5908. '1' => {
  5909. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  5910. 'description' => 'test file'
  5911. }
  5912. }
  5913. }
  5914. )
  5915. end
  5916. end
  5917. assert_redirected_to :action => 'show', :id => '1'
  5918. j = Issue.find(1).journals.reorder('id DESC').first
  5919. assert j.notes.blank?
  5920. assert_equal 1, j.details.size
  5921. assert_equal 'testfile.txt', j.details.first.value
  5922. assert_equal User.anonymous, j.user
  5923. attachment = Attachment.order('id DESC').first
  5924. assert_equal Issue.find(1), attachment.container
  5925. assert_equal User.anonymous, attachment.author
  5926. assert_equal 'testfile.txt', attachment.filename
  5927. assert_equal 'text/plain', attachment.content_type
  5928. assert_equal 'test file', attachment.description
  5929. assert_equal 59, attachment.filesize
  5930. assert File.exist?(attachment.diskfile)
  5931. assert_equal 59, File.size(attachment.diskfile)
  5932. mail = ActionMailer::Base.deliveries.last
  5933. assert_mail_body_match 'testfile.txt', mail
  5934. end
  5935. def test_put_update_with_failure_should_save_attachments
  5936. set_tmp_attachments_directory
  5937. @request.session[:user_id] = 2
  5938. assert_no_difference 'Journal.count' do
  5939. assert_difference 'Attachment.count' do
  5940. put(
  5941. :update,
  5942. :params => {
  5943. :id => 1,
  5944. :issue => {
  5945. :subject => ''
  5946. },
  5947. :attachments => {
  5948. '1' => {
  5949. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  5950. 'description' => 'test file'
  5951. }
  5952. }
  5953. }
  5954. )
  5955. assert_response :success
  5956. end
  5957. end
  5958. attachment = Attachment.order('id DESC').first
  5959. assert_equal 'testfile.txt', attachment.filename
  5960. assert File.exist?(attachment.diskfile)
  5961. assert_nil attachment.container
  5962. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  5963. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  5964. end
  5965. def test_put_update_with_failure_should_keep_saved_attachments
  5966. set_tmp_attachments_directory
  5967. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  5968. @request.session[:user_id] = 2
  5969. assert_no_difference 'Journal.count' do
  5970. assert_no_difference 'Attachment.count' do
  5971. put(
  5972. :update,
  5973. :params => {
  5974. :id => 1,
  5975. :issue => {
  5976. :subject => ''
  5977. },
  5978. :attachments => {
  5979. 'p0' => {
  5980. 'token' => attachment.token
  5981. }
  5982. }
  5983. }
  5984. )
  5985. assert_response :success
  5986. end
  5987. end
  5988. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  5989. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  5990. end
  5991. def test_put_update_should_attach_saved_attachments
  5992. set_tmp_attachments_directory
  5993. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  5994. @request.session[:user_id] = 2
  5995. assert_difference 'Journal.count' do
  5996. assert_difference 'JournalDetail.count' do
  5997. assert_no_difference 'Attachment.count' do
  5998. put(
  5999. :update,
  6000. :params => {
  6001. :id => 1,
  6002. :issue => {
  6003. :notes => 'Attachment added'
  6004. },
  6005. :attachments => {
  6006. 'p0' => {
  6007. 'token' => attachment.token
  6008. }
  6009. }
  6010. }
  6011. )
  6012. assert_redirected_to '/issues/1'
  6013. end
  6014. end
  6015. end
  6016. attachment.reload
  6017. assert_equal Issue.find(1), attachment.container
  6018. journal = Journal.order('id DESC').first
  6019. assert_equal 1, journal.details.size
  6020. assert_equal 'testfile.txt', journal.details.first.value
  6021. end
  6022. def test_put_update_with_attachment_that_fails_to_save
  6023. set_tmp_attachments_directory
  6024. # anonymous user
  6025. with_settings :attachment_max_size => 0 do
  6026. put(
  6027. :update,
  6028. :params => {
  6029. :id => 1,
  6030. :issue => {
  6031. :notes => ''
  6032. },
  6033. :attachments => {
  6034. '1' => {
  6035. 'file' => uploaded_test_file('testfile.txt', 'text/plain')
  6036. }
  6037. }
  6038. }
  6039. )
  6040. assert_redirected_to :action => 'show', :id => '1'
  6041. assert_equal '1 file(s) could not be saved.', flash[:warning]
  6042. end
  6043. end
  6044. def test_put_update_with_attachment_deletion_should_create_a_single_journal
  6045. set_tmp_attachments_directory
  6046. ActionMailer::Base.deliveries.clear
  6047. @request.session[:user_id] = 2
  6048. journal = new_record(Journal) do
  6049. assert_difference 'Attachment.count', -2 do
  6050. put(
  6051. :update,
  6052. :params => {
  6053. :id => 3,
  6054. :issue => {
  6055. :notes => 'Removing attachments',
  6056. :deleted_attachment_ids => ['1', '5']
  6057. }
  6058. }
  6059. )
  6060. end
  6061. end
  6062. assert_equal 'Removing attachments', journal.notes
  6063. assert_equal 2, journal.details.count
  6064. assert_select_email do
  6065. assert_select 'ul.journal.details li', 2
  6066. assert_select 'del', :text => 'error281.txt'
  6067. assert_select 'del', :text => 'changeset_iso8859-1.diff'
  6068. end
  6069. end
  6070. def test_put_update_with_attachment_deletion_and_failure_should_preserve_selected_attachments
  6071. set_tmp_attachments_directory
  6072. @request.session[:user_id] = 2
  6073. assert_no_difference 'Journal.count' do
  6074. assert_no_difference 'Attachment.count' do
  6075. put(
  6076. :update,
  6077. :params => {
  6078. :id => 3,
  6079. :issue => {
  6080. :subject => '',
  6081. :notes => 'Removing attachments',
  6082. :deleted_attachment_ids => ['1', '5']
  6083. }
  6084. }
  6085. )
  6086. end
  6087. end
  6088. assert_select 'input[name=?][value="1"][checked=checked]', 'issue[deleted_attachment_ids][]'
  6089. assert_select 'input[name=?][value="5"][checked=checked]', 'issue[deleted_attachment_ids][]'
  6090. assert_select 'input[name=?][value="6"]:not([checked])', 'issue[deleted_attachment_ids][]'
  6091. end
  6092. def test_put_update_with_no_change
  6093. issue = Issue.find(1)
  6094. issue.journals.clear
  6095. ActionMailer::Base.deliveries.clear
  6096. put(
  6097. :update,
  6098. :params => {
  6099. :id => 1,
  6100. :issue => {
  6101. :notes => ''
  6102. }
  6103. }
  6104. )
  6105. assert_redirected_to :action => 'show', :id => '1'
  6106. issue.reload
  6107. assert issue.journals.empty?
  6108. # No email should be sent
  6109. assert ActionMailer::Base.deliveries.empty?
  6110. end
  6111. def test_put_update_should_send_a_notification
  6112. @request.session[:user_id] = 2
  6113. ActionMailer::Base.deliveries.clear
  6114. issue = Issue.find(1)
  6115. old_subject = issue.subject
  6116. new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
  6117. with_settings :notified_events => %w(issue_updated) do
  6118. put(
  6119. :update,
  6120. :params => {
  6121. :id => 1,
  6122. :issue => {
  6123. :subject => new_subject,
  6124. :priority_id => '6',
  6125. :category_id => '1' # no change
  6126. }
  6127. }
  6128. )
  6129. assert_equal 2, ActionMailer::Base.deliveries.size
  6130. end
  6131. end
  6132. def test_put_update_with_invalid_spent_time_hours_only
  6133. @request.session[:user_id] = 2
  6134. notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
  6135. assert_no_difference('Journal.count') do
  6136. put(
  6137. :update,
  6138. :params => {
  6139. :id => 1,
  6140. :issue => {
  6141. :notes => notes
  6142. },
  6143. :time_entry => {
  6144. "comments"=>"", "activity_id"=>"", "hours"=>"2z"
  6145. }
  6146. }
  6147. )
  6148. end
  6149. assert_response :success
  6150. assert_select_error /Activity cannot be blank/
  6151. assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
  6152. assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
  6153. end
  6154. def test_put_update_with_invalid_spent_time_comments_only
  6155. @request.session[:user_id] = 2
  6156. notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
  6157. assert_no_difference('Journal.count') do
  6158. put(
  6159. :update,
  6160. :params => {
  6161. :id => 1,
  6162. :issue => {
  6163. :notes => notes
  6164. },
  6165. :time_entry => {
  6166. "comments"=>"this is my comment", "activity_id"=>"", "hours"=>""
  6167. }
  6168. }
  6169. )
  6170. end
  6171. assert_response :success
  6172. assert_select_error /Activity cannot be blank/
  6173. assert_select_error /Hours cannot be blank/
  6174. assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
  6175. assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
  6176. end
  6177. def test_put_with_spent_time_when_assigned_to_of_private_issue_is_update_at_the_same_time
  6178. @request.session[:user_id] = 3
  6179. Role.find(2).update! :issues_visibility => 'own'
  6180. private_issue = Issue.find(3)
  6181. assert_difference('TimeEntry.count', 1) do
  6182. put(
  6183. :update,
  6184. params: {
  6185. id: private_issue.id,
  6186. issue: { assigned_to_id: nil },
  6187. time_entry: {
  6188. comments: "add spent time", activity_id: TimeEntryActivity.first.id, hours: 1
  6189. }
  6190. }
  6191. )
  6192. end
  6193. assert_select '#errorExplanation', {text: /Log time is invalid/, count: 0}
  6194. assert_select '#errorExplanation', {text: /Issue is invalid/, count: 0}
  6195. assert_redirected_to action: 'show', id: private_issue.id
  6196. assert_not private_issue.reload.visible?
  6197. end
  6198. def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
  6199. issue = Issue.find(2)
  6200. @request.session[:user_id] = 2
  6201. put(
  6202. :update,
  6203. :params => {
  6204. :id => issue.id,
  6205. :issue => {
  6206. :fixed_version_id => 4
  6207. }
  6208. }
  6209. )
  6210. assert_response :redirect
  6211. issue.reload
  6212. assert_equal 4, issue.fixed_version_id
  6213. assert_not_equal issue.project_id, issue.fixed_version.project_id
  6214. end
  6215. def test_put_update_should_redirect_back_using_the_back_url_parameter
  6216. issue = Issue.find(2)
  6217. @request.session[:user_id] = 2
  6218. put(
  6219. :update,
  6220. :params => {
  6221. :id => issue.id,
  6222. :issue => {
  6223. :fixed_version_id => 4
  6224. },
  6225. :back_url => '/issues'
  6226. }
  6227. )
  6228. assert_response :redirect
  6229. assert_redirected_to '/issues'
  6230. end
  6231. def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  6232. issue = Issue.find(2)
  6233. @request.session[:user_id] = 2
  6234. put(
  6235. :update,
  6236. :params => {
  6237. :id => issue.id,
  6238. :issue => {
  6239. :fixed_version_id => 4
  6240. },
  6241. :back_url => 'http://google.com'
  6242. }
  6243. )
  6244. assert_response :redirect
  6245. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
  6246. end
  6247. def test_put_update_should_redirect_with_previous_and_next_issue_ids_params
  6248. @request.session[:user_id] = 2
  6249. put(
  6250. :update,
  6251. :params => {
  6252. :id => 11,
  6253. :issue => {
  6254. :status_id => 6,
  6255. :notes => 'Notes'
  6256. },
  6257. :prev_issue_id => 8,
  6258. :next_issue_id => 12,
  6259. :issue_position => 2,
  6260. :issue_count => 3
  6261. }
  6262. )
  6263. assert_redirected_to '/issues/11?issue_count=3&issue_position=2&next_issue_id=12&prev_issue_id=8'
  6264. end
  6265. def test_update_with_permission_on_tracker_should_be_allowed
  6266. role = Role.find(1)
  6267. role.set_permission_trackers :edit_issues, [1]
  6268. role.save!
  6269. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :subject => 'Original subject')
  6270. @request.session[:user_id] = 2
  6271. put(
  6272. :update,
  6273. :params => {
  6274. :id => issue.id,
  6275. :issue => {
  6276. :subject => 'Changed subject'
  6277. }
  6278. }
  6279. )
  6280. assert_response :found
  6281. assert_equal 'Changed subject', issue.reload.subject
  6282. end
  6283. def test_update_without_permission_on_tracker_should_be_denied
  6284. role = Role.find(1)
  6285. role.set_permission_trackers :edit_issues, [1]
  6286. role.save!
  6287. issue = Issue.generate!(:project_id => 1, :tracker_id => 2, :subject => 'Original subject')
  6288. @request.session[:user_id] = 2
  6289. put(
  6290. :update,
  6291. :params => {
  6292. :id => issue.id,
  6293. :issue => {
  6294. :subject => 'Changed subject'
  6295. }
  6296. }
  6297. )
  6298. assert_response :found
  6299. assert_equal 'Original subject', issue.reload.subject
  6300. end
  6301. def test_update_with_me_assigned_to_id
  6302. @request.session[:user_id] = 2
  6303. issue = Issue.find(1)
  6304. assert_not_equal 2, issue.assigned_to_id
  6305. put(
  6306. :update,
  6307. :params => {
  6308. :id => issue.id,
  6309. :issue => {
  6310. :assigned_to_id => 'me'
  6311. }
  6312. }
  6313. )
  6314. assert_response :found
  6315. assert_equal 2, issue.reload.assigned_to_id
  6316. end
  6317. def test_update_with_value_of_none_should_set_the_values_to_blank
  6318. @request.session[:user_id] = 2
  6319. issue = Issue.find(1)
  6320. issue.custom_field_values = {1 => 'MySQL'}
  6321. issue.assigned_to_id = 2
  6322. issue.save!
  6323. put(
  6324. :update,
  6325. params: {
  6326. id: issue.id,
  6327. issue: {
  6328. assigned_to_id: 'none',
  6329. category_id: 'none',
  6330. fixed_version_id: 'none',
  6331. custom_field_values: { 1 => '__none__' }
  6332. }
  6333. }
  6334. )
  6335. issue.reload
  6336. assert_nil issue.assigned_to
  6337. assert_nil issue.category
  6338. assert_nil issue.fixed_version
  6339. assert_equal '', issue.custom_field_value(1)
  6340. end
  6341. def test_get_bulk_edit
  6342. @request.session[:user_id] = 2
  6343. get(:bulk_edit, :params => {:ids => [1, 3]})
  6344. assert_response :success
  6345. assert_select 'ul#bulk-selection' do
  6346. assert_select 'li', 2
  6347. assert_select 'li a', :text => 'Bug #1'
  6348. end
  6349. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6350. assert_select 'input[name=?]', 'ids[]', 2
  6351. assert_select 'input[name=?][value="1"][type=hidden]', 'ids[]'
  6352. assert_select 'select[name=?]', 'issue[project_id]'
  6353. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  6354. # Project specific custom field, date type
  6355. field = CustomField.find(9)
  6356. assert !field.is_for_all?
  6357. assert_equal 'date', field.field_format
  6358. assert_select 'input[name=?]', 'issue[custom_field_values][9]'
  6359. # System wide custom field
  6360. assert CustomField.find(1).is_for_all?
  6361. assert_select 'select[name=?]', 'issue[custom_field_values][1]'
  6362. # Be sure we don't display inactive IssuePriorities
  6363. assert_not IssuePriority.find(15).active?
  6364. assert_select 'select[name=?]', 'issue[priority_id]' do
  6365. assert_select 'option[value="15"]', 0
  6366. end
  6367. # Initial form should hide 'follow' button
  6368. assert_select 'input[type=submit]', 1 do
  6369. assert_select '[name=?]', 'commit', 1
  6370. assert_select '[name=?]', 'follow', 0
  6371. end
  6372. end
  6373. end
  6374. test "bulk_edit should show follow button when project is selected" do
  6375. @request.session[:user_id] = 2
  6376. post(
  6377. :bulk_edit,
  6378. :params => {
  6379. :ids => [1, 3],
  6380. :issue => {
  6381. :project_id => 2,
  6382. }
  6383. }
  6384. )
  6385. assert_response :success
  6386. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6387. assert_select 'input[type=submit]', 2 do
  6388. assert_select '[name=?]', 'commit', 1
  6389. assert_select '[name=?]', 'follow', 1
  6390. end
  6391. end
  6392. end
  6393. test "bulk_edit should hide follow button when project is not changed" do
  6394. @request.session[:user_id] = 2
  6395. post(
  6396. :bulk_edit,
  6397. :params => {
  6398. :ids => [1, 3],
  6399. :issue => {
  6400. :project_id => "",
  6401. }
  6402. }
  6403. )
  6404. assert_response :success
  6405. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6406. assert_select 'input[type=submit]', 1 do
  6407. assert_select '[name=?]', 'commit', 1
  6408. assert_select '[name=?]', 'follow', 0
  6409. end
  6410. end
  6411. end
  6412. def test_get_bulk_edit_on_different_projects
  6413. @request.session[:user_id] = 2
  6414. get(:bulk_edit, :params => {:ids => [1, 2, 6]})
  6415. assert_response :success
  6416. # Can not set issues from different projects as children of an issue
  6417. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  6418. # Project specific custom field, date type
  6419. field = CustomField.find(9)
  6420. assert !field.is_for_all?
  6421. assert !field.project_ids.include?(Issue.find(6).project_id)
  6422. assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
  6423. end
  6424. def test_get_bulk_edit_with_user_custom_field
  6425. field =
  6426. IssueCustomField.
  6427. create!(
  6428. :name => 'Tester',
  6429. :field_format => 'user',
  6430. :is_for_all => true,
  6431. :tracker_ids => [1, 2, 3]
  6432. )
  6433. @request.session[:user_id] = 2
  6434. get(:bulk_edit, :params => {:ids => [1, 2]})
  6435. assert_response :success
  6436. assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
  6437. assert_select 'option', Project.find(1).users.count + 3 # "no change" + "none" + "me" options
  6438. end
  6439. end
  6440. def test_get_bulk_edit_with_version_custom_field
  6441. field =
  6442. IssueCustomField.
  6443. create!(
  6444. :name => 'Affected version',
  6445. :field_format => 'version',
  6446. :is_for_all => true,
  6447. :tracker_ids => [1, 2, 3]
  6448. )
  6449. @request.session[:user_id] = 2
  6450. get(:bulk_edit, :params => {:ids => [1, 2]})
  6451. assert_response :success
  6452. assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
  6453. assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
  6454. end
  6455. end
  6456. def test_get_bulk_edit_with_multi_custom_field
  6457. field = CustomField.find(1)
  6458. field.update_attribute :multiple, true
  6459. @request.session[:user_id] = 2
  6460. get(:bulk_edit, :params => {:ids => [1, 3]})
  6461. assert_response :success
  6462. assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
  6463. assert_select 'option', field.possible_values.size + 1 # "none" options
  6464. end
  6465. end
  6466. def test_bulk_edit_should_propose_to_clear_text_custom_fields
  6467. @request.session[:user_id] = 2
  6468. get(:bulk_edit, :params => {:ids => [1, 3]})
  6469. assert_response :success
  6470. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', '__none__'
  6471. end
  6472. def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
  6473. WorkflowTransition.delete_all
  6474. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6475. :old_status_id => 1, :new_status_id => 1)
  6476. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6477. :old_status_id => 1, :new_status_id => 3)
  6478. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6479. :old_status_id => 1, :new_status_id => 4)
  6480. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6481. :old_status_id => 2, :new_status_id => 1)
  6482. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6483. :old_status_id => 2, :new_status_id => 3)
  6484. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6485. :old_status_id => 2, :new_status_id => 5)
  6486. @request.session[:user_id] = 2
  6487. get(:bulk_edit, :params => {:ids => [1, 2]})
  6488. assert_select 'select[name=?]', 'issue[status_id]' do
  6489. assert_select 'option[value=""]'
  6490. assert_select 'option[value="1"]'
  6491. assert_select 'option[value="3"]'
  6492. assert_select 'option', 3 # 2 statuses + "no change" option
  6493. end
  6494. end
  6495. def test_bulk_edit_should_propose_target_project_open_shared_versions
  6496. @request.session[:user_id] = 2
  6497. post(
  6498. :bulk_edit,
  6499. :params => {
  6500. :ids => [1, 2, 6],
  6501. :issue => {
  6502. :project_id => 1
  6503. }
  6504. }
  6505. )
  6506. assert_response :success
  6507. expected_versions = Project.find(1).shared_versions.open.to_a.sort
  6508. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  6509. expected_versions.each do |version|
  6510. assert_select 'option[value=?]', version.id.to_s
  6511. end
  6512. assert_select 'option[value=""]'
  6513. assert_select 'option[value="none"]'
  6514. assert_select 'option', expected_versions.size + 2
  6515. end
  6516. end
  6517. def test_bulk_edit_should_propose_target_project_categories
  6518. @request.session[:user_id] = 2
  6519. post(
  6520. :bulk_edit,
  6521. :params => {
  6522. :ids => [1, 2, 6],
  6523. :issue => {
  6524. :project_id => 1
  6525. }
  6526. }
  6527. )
  6528. assert_response :success
  6529. expected_categories = Project.find(1).issue_categories.sort
  6530. assert_select 'select[name=?]', 'issue[category_id]' do
  6531. expected_categories.each do |category|
  6532. assert_select 'option[value=?]', category.id.to_s
  6533. end
  6534. assert_select 'option[value=""]'
  6535. assert_select 'option[value="none"]'
  6536. assert_select 'option', expected_categories.size + 2
  6537. end
  6538. end
  6539. def test_bulk_edit_should_only_propose_issues_trackers_custom_fields
  6540. IssueCustomField.delete_all
  6541. field1 = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
  6542. field2 = IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
  6543. @request.session[:user_id] = 2
  6544. issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
  6545. get(
  6546. :bulk_edit,
  6547. :params => {
  6548. :ids => issue_ids
  6549. }
  6550. )
  6551. assert_response :success
  6552. assert_select 'input[name=?]', "issue[custom_field_values][#{field1.id}]"
  6553. assert_select 'input[name=?]', "issue[custom_field_values][#{field2.id}]", 0
  6554. end
  6555. def test_bulk_edit_should_propose_target_tracker_custom_fields
  6556. IssueCustomField.delete_all
  6557. field1 = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
  6558. field2 = IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
  6559. @request.session[:user_id] = 2
  6560. issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
  6561. get(
  6562. :bulk_edit,
  6563. :params => {
  6564. :ids => issue_ids,
  6565. :issue => {
  6566. :tracker_id => 2
  6567. }
  6568. }
  6569. )
  6570. assert_response :success
  6571. assert_select 'input[name=?]', "issue[custom_field_values][#{field1.id}]", 0
  6572. assert_select 'input[name=?]', "issue[custom_field_values][#{field2.id}]"
  6573. end
  6574. def test_bulk_edit_should_warn_about_custom_field_values_about_to_be_cleared
  6575. CustomField.destroy_all
  6576. cleared = IssueCustomField.generate!(:name => 'Cleared',
  6577. :tracker_ids => [2],
  6578. :is_for_all => true)
  6579. CustomValue.create!(:customized => Issue.find(2),
  6580. :custom_field => cleared,
  6581. :value => 'foo')
  6582. not_cleared = IssueCustomField.generate!(:name => 'Not cleared',
  6583. :tracker_ids => [2, 3],
  6584. :is_for_all => true)
  6585. CustomValue.create!(:customized => Issue.find(2),
  6586. :custom_field => not_cleared,
  6587. :value => 'bar')
  6588. @request.session[:user_id] = 2
  6589. get(
  6590. :bulk_edit,
  6591. :params => {
  6592. :ids => [1, 2],
  6593. :issue => {
  6594. :tracker_id => 3
  6595. }
  6596. }
  6597. )
  6598. assert_response :success
  6599. assert_select '.warning', :text => /automatic deletion of values/
  6600. assert_select '.warning span', :text => 'Cleared (1)'
  6601. assert_select '.warning span', :text => /Not cleared/, :count => 0
  6602. end
  6603. def test_bulk_update
  6604. @request.session[:user_id] = 2
  6605. # update issues priority
  6606. post(
  6607. :bulk_update,
  6608. :params => {
  6609. :ids => [1, 2],
  6610. :notes => 'Bulk editing',
  6611. :issue => {
  6612. :priority_id => 7,
  6613. :assigned_to_id => '',
  6614. :custom_field_values => {
  6615. '2' => ''
  6616. }
  6617. }
  6618. }
  6619. )
  6620. assert_response :found
  6621. # check that the issues were updated
  6622. assert_equal [7, 7], Issue.where(:id =>[1, 2]).collect {|i| i.priority.id}
  6623. issue = Issue.find(1)
  6624. journal = issue.journals.reorder('created_on DESC').first
  6625. assert_equal '125', issue.custom_value_for(2).value
  6626. assert_equal 'Bulk editing', journal.notes
  6627. assert_equal 1, journal.details.size
  6628. end
  6629. def test_bulk_update_with_group_assignee
  6630. group = Group.find(11)
  6631. project = Project.find(1)
  6632. project.members << Member.new(:principal => group, :roles => [Role.givable.first])
  6633. @request.session[:user_id] = 2
  6634. # update issues assignee
  6635. with_settings :issue_group_assignment => '1' do
  6636. post(
  6637. :bulk_update,
  6638. :params => {
  6639. :ids => [1, 2],
  6640. :notes => 'Bulk editing',
  6641. :issue => {
  6642. :priority_id => '',
  6643. :assigned_to_id => group.id,
  6644. :custom_field_values => {
  6645. '2' => ''
  6646. }
  6647. }
  6648. }
  6649. )
  6650. assert_response :found
  6651. assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
  6652. end
  6653. end
  6654. def test_bulk_update_on_different_projects
  6655. @request.session[:user_id] = 2
  6656. # update issues priority
  6657. post(
  6658. :bulk_update,
  6659. :params => {
  6660. :ids => [1, 2, 6],
  6661. :notes => 'Bulk editing',
  6662. :issue => {
  6663. :priority_id => 7,
  6664. :assigned_to_id => '',
  6665. :custom_field_values => {
  6666. '2' => ''
  6667. }
  6668. }
  6669. }
  6670. )
  6671. assert_response :found
  6672. # check that the issues were updated
  6673. assert_equal [7, 7, 7], Issue.find([1, 2, 6]).map(&:priority_id)
  6674. issue = Issue.find(1)
  6675. journal = issue.journals.reorder('created_on DESC').first
  6676. assert_equal '125', issue.custom_value_for(2).value
  6677. assert_equal 'Bulk editing', journal.notes
  6678. assert_equal 1, journal.details.size
  6679. end
  6680. def test_bulk_update_on_different_projects_without_rights
  6681. @request.session[:user_id] = 3
  6682. user = User.find(3)
  6683. action = {:controller => "issues", :action => "bulk_update"}
  6684. assert user.allowed_to?(action, Issue.find(1).project)
  6685. assert_not user.allowed_to?(action, Issue.find(6).project)
  6686. post(
  6687. :bulk_update,
  6688. :params => {
  6689. :ids => [1, 6],
  6690. :notes => 'Bulk should fail',
  6691. :issue => {
  6692. :priority_id => 7,
  6693. :assigned_to_id => '',
  6694. :custom_field_values => {
  6695. '2' => ''
  6696. }
  6697. }
  6698. }
  6699. )
  6700. assert_response :forbidden
  6701. assert_not_equal "Bulk should fail", Journal.last.notes
  6702. end
  6703. def test_bulk_update_should_send_a_notification
  6704. @request.session[:user_id] = 2
  6705. ActionMailer::Base.deliveries.clear
  6706. with_settings :notified_events => %w(issue_updated) do
  6707. post(
  6708. :bulk_update,
  6709. :params => {
  6710. :ids => [1, 2],
  6711. :notes => 'Bulk editing',
  6712. :issue => {
  6713. :priority_id => 7,
  6714. :assigned_to_id => '',
  6715. :custom_field_values => {'2' => ''}
  6716. }
  6717. }
  6718. )
  6719. assert_response :found
  6720. # 4 emails for 2 members and 2 issues
  6721. # 1 email for a watcher of issue #2
  6722. assert_equal 5, ActionMailer::Base.deliveries.size
  6723. end
  6724. end
  6725. def test_bulk_update_project
  6726. @request.session[:user_id] = 2
  6727. post(
  6728. :bulk_update,
  6729. :params => {
  6730. :ids => [1, 2],
  6731. :issue => {
  6732. :project_id => '2'
  6733. }
  6734. }
  6735. )
  6736. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6737. # Issues moved to project 2
  6738. assert_equal 2, Issue.find(1).project_id
  6739. assert_equal 2, Issue.find(2).project_id
  6740. # No tracker change
  6741. assert_equal 1, Issue.find(1).tracker_id
  6742. assert_equal 2, Issue.find(2).tracker_id
  6743. end
  6744. def test_bulk_update_project_on_single_issue_should_follow_when_needed
  6745. @request.session[:user_id] = 2
  6746. post(
  6747. :bulk_update,
  6748. :params => {
  6749. :id => 1,
  6750. :issue => {
  6751. :project_id => '2'
  6752. },
  6753. :follow => '1'
  6754. }
  6755. )
  6756. assert_redirected_to '/issues/1'
  6757. end
  6758. def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
  6759. @request.session[:user_id] = 2
  6760. post(
  6761. :bulk_update,
  6762. :params => {
  6763. :id => [1, 2],
  6764. :issue => {
  6765. :project_id => '2'
  6766. },
  6767. :follow => '1'
  6768. }
  6769. )
  6770. assert_redirected_to '/projects/onlinestore/issues'
  6771. end
  6772. def test_bulk_update_tracker
  6773. @request.session[:user_id] = 2
  6774. post(
  6775. :bulk_update, :params => {
  6776. :ids => [1, 2],
  6777. :issue => {
  6778. :tracker_id => '2'
  6779. }
  6780. }
  6781. )
  6782. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6783. assert_equal 2, Issue.find(1).tracker_id
  6784. assert_equal 2, Issue.find(2).tracker_id
  6785. end
  6786. def test_bulk_update_status
  6787. @request.session[:user_id] = 2
  6788. # update issues priority
  6789. post(
  6790. :bulk_update,
  6791. :params => {
  6792. :ids => [1, 2],
  6793. :notes => 'Bulk editing status',
  6794. :issue => {
  6795. :priority_id => '',
  6796. :assigned_to_id => '',
  6797. :status_id => '5'
  6798. }
  6799. }
  6800. )
  6801. assert_response :found
  6802. issue = Issue.find(1)
  6803. assert issue.closed?
  6804. end
  6805. def test_bulk_update_priority
  6806. @request.session[:user_id] = 2
  6807. post(
  6808. :bulk_update,
  6809. :params => {
  6810. :ids => [1, 2],
  6811. :issue => {
  6812. :priority_id => 6
  6813. }
  6814. }
  6815. )
  6816. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6817. assert_equal 6, Issue.find(1).priority_id
  6818. assert_equal 6, Issue.find(2).priority_id
  6819. end
  6820. def test_bulk_update_with_notes
  6821. @request.session[:user_id] = 2
  6822. post(
  6823. :bulk_update,
  6824. :params => {
  6825. :ids => [1, 2],
  6826. :notes => 'Moving two issues'
  6827. }
  6828. )
  6829. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6830. assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
  6831. assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
  6832. assert_equal false, Issue.find(1).journals.sort_by(&:id).last.private_notes
  6833. assert_equal false, Issue.find(2).journals.sort_by(&:id).last.private_notes
  6834. end
  6835. def test_bulk_update_with_private_notes
  6836. @request.session[:user_id] = 2
  6837. post(
  6838. :bulk_update,
  6839. :params => {
  6840. :ids => [1, 2],
  6841. :notes => 'Moving two issues',
  6842. :issue => {:private_notes => 'true'}
  6843. }
  6844. )
  6845. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6846. assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
  6847. assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
  6848. assert_equal true, Issue.find(1).journals.sort_by(&:id).last.private_notes
  6849. assert_equal true, Issue.find(2).journals.sort_by(&:id).last.private_notes
  6850. end
  6851. def test_bulk_update_parent_id
  6852. IssueRelation.delete_all
  6853. @request.session[:user_id] = 2
  6854. post(
  6855. :bulk_update,
  6856. :params => {
  6857. :ids => [1, 3],
  6858. :notes => 'Bulk editing parent',
  6859. :issue => {
  6860. :priority_id => '',
  6861. :assigned_to_id => '',
  6862. :status_id => '',
  6863. :parent_issue_id => '2'
  6864. }
  6865. }
  6866. )
  6867. assert_response :found
  6868. parent = Issue.find(2)
  6869. assert_equal parent.id, Issue.find(1).parent_id
  6870. assert_equal parent.id, Issue.find(3).parent_id
  6871. assert_equal [1, 3], parent.children.collect(&:id).sort
  6872. end
  6873. def test_bulk_update_estimated_hours
  6874. @request.session[:user_id] = 2
  6875. post(
  6876. :bulk_update,
  6877. :params => {
  6878. :ids => [1, 2],
  6879. :issue => {
  6880. :estimated_hours => 4.25
  6881. }
  6882. }
  6883. )
  6884. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6885. assert_equal 4.25, Issue.find(1).estimated_hours
  6886. assert_equal 4.25, Issue.find(2).estimated_hours
  6887. end
  6888. def test_bulk_update_custom_field
  6889. @request.session[:user_id] = 2
  6890. # update issues priority
  6891. post(
  6892. :bulk_update,
  6893. :params => {
  6894. :ids => [1, 2],
  6895. :notes => 'Bulk editing custom field',
  6896. :issue => {
  6897. :priority_id => '',
  6898. :assigned_to_id => '',
  6899. :custom_field_values => {
  6900. '2' => '777'
  6901. }
  6902. }
  6903. }
  6904. )
  6905. assert_response :found
  6906. issue = Issue.find(1)
  6907. journal = issue.journals.reorder('created_on DESC').first
  6908. assert_equal '777', issue.custom_value_for(2).value
  6909. assert_equal 1, journal.details.size
  6910. assert_equal '125', journal.details.first.old_value
  6911. assert_equal '777', journal.details.first.value
  6912. end
  6913. def test_bulk_update_custom_field_to_blank
  6914. @request.session[:user_id] = 2
  6915. post(
  6916. :bulk_update,
  6917. :params => {
  6918. :ids => [1, 3],
  6919. :notes => 'Bulk editing custom field',
  6920. :issue => {
  6921. :priority_id => '',
  6922. :assigned_to_id => '',
  6923. :custom_field_values => {
  6924. '1' => '__none__'
  6925. }
  6926. }
  6927. }
  6928. )
  6929. assert_response :found
  6930. assert_equal '', Issue.find(1).custom_field_value(1)
  6931. assert_equal '', Issue.find(3).custom_field_value(1)
  6932. end
  6933. def test_bulk_update_multi_custom_field
  6934. field = CustomField.find(1)
  6935. field.update_attribute :multiple, true
  6936. @request.session[:user_id] = 2
  6937. post(
  6938. :bulk_update,
  6939. :params => {
  6940. :ids => [1, 2, 3],
  6941. :notes => 'Bulk editing multi custom field',
  6942. :issue => {
  6943. :priority_id => '',
  6944. :assigned_to_id => '',
  6945. :custom_field_values => {
  6946. '1' => ['MySQL', 'Oracle']
  6947. }
  6948. }
  6949. }
  6950. )
  6951. assert_response :found
  6952. assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
  6953. assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
  6954. # the custom field is not associated with the issue tracker
  6955. assert_nil Issue.find(2).custom_field_value(1)
  6956. end
  6957. def test_bulk_update_multi_custom_field_to_blank
  6958. field = CustomField.find(1)
  6959. field.update_attribute :multiple, true
  6960. @request.session[:user_id] = 2
  6961. post(
  6962. :bulk_update,
  6963. :params => {
  6964. :ids => [1, 3],
  6965. :notes => 'Bulk editing multi custom field',
  6966. :issue => {
  6967. :priority_id => '',
  6968. :assigned_to_id => '',
  6969. :custom_field_values => {
  6970. '1' => ['__none__']
  6971. }
  6972. }
  6973. }
  6974. )
  6975. assert_response :found
  6976. assert_equal [''], Issue.find(1).custom_field_value(1)
  6977. assert_equal [''], Issue.find(3).custom_field_value(1)
  6978. end
  6979. def test_bulk_update_unassign
  6980. assert_not_nil Issue.find(2).assigned_to
  6981. @request.session[:user_id] = 2
  6982. # unassign issues
  6983. post(
  6984. :bulk_update,
  6985. :params => {
  6986. :ids => [1, 2],
  6987. :notes => 'Bulk unassigning',
  6988. :issue => {
  6989. :assigned_to_id => 'none'
  6990. }
  6991. }
  6992. )
  6993. assert_response :found
  6994. # check that the issues were updated
  6995. assert_nil Issue.find(2).assigned_to
  6996. end
  6997. def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
  6998. @request.session[:user_id] = 2
  6999. post(
  7000. :bulk_update,
  7001. :params => {
  7002. :ids => [1, 2],
  7003. :issue => {
  7004. :fixed_version_id => 4
  7005. }
  7006. }
  7007. )
  7008. assert_response :redirect
  7009. issues = Issue.find([1, 2])
  7010. issues.each do |issue|
  7011. assert_equal 4, issue.fixed_version_id
  7012. assert_not_equal issue.project_id, issue.fixed_version.project_id
  7013. end
  7014. end
  7015. def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
  7016. @request.session[:user_id] = 2
  7017. post(
  7018. :bulk_update,
  7019. :params => {
  7020. :ids => [1, 2],
  7021. :back_url => '/issues'
  7022. }
  7023. )
  7024. assert_response :redirect
  7025. assert_redirected_to '/issues'
  7026. end
  7027. def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  7028. @request.session[:user_id] = 2
  7029. post(
  7030. :bulk_update,
  7031. :params => {
  7032. :ids => [1, 2],
  7033. :back_url => 'http://google.com'
  7034. }
  7035. )
  7036. assert_response :redirect
  7037. assert_redirected_to(
  7038. :controller => 'issues', :action => 'index',
  7039. :project_id => Project.find(1).identifier
  7040. )
  7041. end
  7042. def test_bulk_update_with_all_failures_should_show_errors
  7043. @request.session[:user_id] = 2
  7044. post(
  7045. :bulk_update,
  7046. :params => {
  7047. :ids => [1, 2],
  7048. :issue => {
  7049. :start_date => 'foo'
  7050. }
  7051. }
  7052. )
  7053. assert_response :success
  7054. assert_select '#errorExplanation span', :text => 'Failed to save 2 issue(s) on 2 selected: #1, #2.'
  7055. assert_select '#errorExplanation ul li', :text => 'Start date is not a valid date: #1, #2'
  7056. end
  7057. def test_bulk_update_with_some_failures_should_show_errors
  7058. issue1 = Issue.generate!(:start_date => '2013-05-12')
  7059. issue2 = Issue.generate!(:start_date => '2013-05-15')
  7060. issue3 = Issue.generate!
  7061. @request.session[:user_id] = 2
  7062. post(
  7063. :bulk_update,
  7064. :params => {
  7065. :ids => [issue1.id, issue2.id, issue3.id],
  7066. :issue => {
  7067. :due_date => '2013-05-01'
  7068. }
  7069. }
  7070. )
  7071. assert_response :success
  7072. assert_select '#errorExplanation span',
  7073. :text => "Failed to save 2 issue(s) on 3 selected: ##{issue1.id}, ##{issue2.id}."
  7074. assert_select '#errorExplanation ul li',
  7075. :text => "Due date must be greater than start date: ##{issue1.id}, ##{issue2.id}"
  7076. assert_select '#bulk-selection li', 2
  7077. end
  7078. def test_bulk_update_with_failure_should_preserved_form_values
  7079. @request.session[:user_id] = 2
  7080. post(
  7081. :bulk_update,
  7082. :params => {
  7083. :ids => [1, 2],
  7084. :issue => {
  7085. :tracker_id => '2',
  7086. :start_date => 'foo'
  7087. }
  7088. }
  7089. )
  7090. assert_response :success
  7091. assert_select 'select[name=?]', 'issue[tracker_id]' do
  7092. assert_select 'option[value="2"][selected=selected]'
  7093. end
  7094. assert_select 'input[name=?][value=?]', 'issue[start_date]', 'foo'
  7095. end
  7096. def test_get_bulk_copy
  7097. assert_not Issue.find(1).attachments.any?
  7098. assert Issue.find(2).attachments.any?
  7099. assert Issue.find(3).attachments.any?
  7100. @request.session[:user_id] = 2
  7101. get(
  7102. :bulk_edit,
  7103. :params => {
  7104. :ids => [1, 2, 3],
  7105. :copy => '1'
  7106. }
  7107. )
  7108. assert_response :success
  7109. assert_select '#bulk-selection li', 3
  7110. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7111. assert_select 'select[name=?]', 'issue[project_id]' do
  7112. assert_select 'option[value=""]'
  7113. end
  7114. assert_select 'input[name=copy_attachments]'
  7115. end
  7116. end
  7117. test "bulk copy should show follow button when project is selected" do
  7118. @request.session[:user_id] = 2
  7119. post(
  7120. :bulk_edit,
  7121. :params => {
  7122. :ids => [1, 3],
  7123. :issue => {
  7124. :project_id => 2,
  7125. },
  7126. :copy => '1',
  7127. }
  7128. )
  7129. assert_response :success
  7130. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7131. assert_select 'input[type=submit]', 2 do
  7132. assert_select '[name=?]', 'commit', 1
  7133. assert_select '[name=?]', 'follow', 1
  7134. end
  7135. end
  7136. end
  7137. def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
  7138. user = setup_user_with_copy_but_not_add_permission
  7139. @request.session[:user_id] = user.id
  7140. get(
  7141. :bulk_edit,
  7142. :params => {
  7143. :ids => [1, 2, 3],
  7144. :copy => '1'
  7145. }
  7146. )
  7147. assert_response :success
  7148. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7149. assert_select 'select[name=?]', 'issue[project_id]' do
  7150. assert_select 'option[value=""]', 0
  7151. assert_select 'option[value="2"]'
  7152. end
  7153. end
  7154. end
  7155. def test_bulk_copy_to_another_project
  7156. @request.session[:user_id] = 2
  7157. issue_ids = [1, 2]
  7158. assert_difference 'Issue.count', issue_ids.size do
  7159. assert_no_difference 'Project.find(1).issues.count' do
  7160. post(
  7161. :bulk_update,
  7162. :params => {
  7163. :ids => issue_ids,
  7164. :issue => {
  7165. :project_id => '2'
  7166. },
  7167. :copy => '1'
  7168. }
  7169. )
  7170. end
  7171. end
  7172. assert_redirected_to '/projects/ecookbook/issues'
  7173. copies = Issue.order('id DESC').limit(issue_ids.size)
  7174. copies.each do |copy|
  7175. assert_equal 2, copy.project_id
  7176. end
  7177. end
  7178. def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
  7179. user = setup_user_with_copy_but_not_add_permission
  7180. @request.session[:user_id] = user.id
  7181. assert_difference 'Issue.count', 3 do
  7182. post(
  7183. :bulk_update,
  7184. :params => {
  7185. :ids => [1, 2, 3],
  7186. :issue => {
  7187. :project_id => '2'
  7188. },
  7189. :copy => '1'
  7190. }
  7191. )
  7192. assert_response :found
  7193. end
  7194. end
  7195. def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
  7196. user = setup_user_with_copy_but_not_add_permission
  7197. @request.session[:user_id] = user.id
  7198. post(
  7199. :bulk_update,
  7200. :params => {
  7201. :ids => [1, 2, 3],
  7202. :issue => {
  7203. :project_id => ''
  7204. },
  7205. :copy => '1'
  7206. }
  7207. )
  7208. assert_response :forbidden
  7209. end
  7210. def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
  7211. user = setup_user_with_copy_but_not_add_permission
  7212. @request.session[:user_id] = user.id
  7213. post(
  7214. :bulk_update,
  7215. :params => {
  7216. :ids => [1, 2, 3],
  7217. :issue => {
  7218. :project_id => '1'
  7219. },
  7220. :copy => '1'
  7221. }
  7222. )
  7223. assert_response :forbidden
  7224. end
  7225. def test_bulk_copy_should_allow_not_changing_the_issue_attributes
  7226. @request.session[:user_id] = 2
  7227. issues = [
  7228. Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1,
  7229. :priority_id => 2, :subject => 'issue 1', :author_id => 1,
  7230. :assigned_to_id => nil),
  7231. Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2,
  7232. :priority_id => 1, :subject => 'issue 2', :author_id => 2,
  7233. :assigned_to_id => 2)
  7234. ]
  7235. assert_difference 'Issue.count', issues.size do
  7236. post(
  7237. :bulk_update,
  7238. :params => {
  7239. :ids => issues.map(&:id),
  7240. :copy => '1',
  7241. :issue => {
  7242. :project_id => '',
  7243. :tracker_id => '',
  7244. :assigned_to_id => '',
  7245. :status_id => '',
  7246. :start_date => '',
  7247. :due_date => ''
  7248. }
  7249. }
  7250. )
  7251. end
  7252. copies = Issue.order('id DESC').limit(issues.size)
  7253. issues.each do |orig|
  7254. copy = copies.detect {|c| c.subject == orig.subject}
  7255. assert_not_nil copy
  7256. assert_equal orig.project_id, copy.project_id
  7257. assert_equal orig.tracker_id, copy.tracker_id
  7258. assert_equal 1, copy.status_id
  7259. if orig.assigned_to_id
  7260. assert_equal orig.assigned_to_id, copy.assigned_to_id
  7261. else
  7262. assert_nil copy.assigned_to_id
  7263. end
  7264. assert_equal orig.priority_id, copy.priority_id
  7265. end
  7266. end
  7267. def test_bulk_copy_should_allow_changing_the_issue_attributes
  7268. # Fixes random test failure with Mysql
  7269. # where Issue.where(:project_id => 2).limit(2).order('id desc')
  7270. # doesn't return the expected results
  7271. Issue.where("project_id=2").delete_all
  7272. @request.session[:user_id] = 2
  7273. assert_difference 'Issue.count', 2 do
  7274. assert_no_difference 'Project.find(1).issues.count' do
  7275. post(
  7276. :bulk_update,
  7277. :params => {
  7278. :ids => [1, 2],
  7279. :copy => '1',
  7280. :issue => {
  7281. :project_id => '2',
  7282. :tracker_id => '',
  7283. :assigned_to_id => '2',
  7284. :status_id => '1',
  7285. :start_date => '2009-12-01',
  7286. :due_date => '2009-12-31'
  7287. }
  7288. }
  7289. )
  7290. end
  7291. end
  7292. copied_issues = Issue.where(:project_id => 2).limit(2).order('id desc').to_a
  7293. assert_equal 2, copied_issues.size
  7294. copied_issues.each do |issue|
  7295. assert_equal 2, issue.project_id, "Project is incorrect"
  7296. assert_equal 2, issue.assigned_to_id, "Assigned to is incorrect"
  7297. assert_equal 1, issue.status_id, "Status is incorrect"
  7298. assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
  7299. assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
  7300. end
  7301. end
  7302. def test_bulk_copy_should_allow_adding_a_note
  7303. @request.session[:user_id] = 2
  7304. assert_difference 'Issue.count', 1 do
  7305. post(
  7306. :bulk_update,
  7307. :params => {
  7308. :ids => [1],
  7309. :copy => '1',
  7310. :notes => 'Copying one issue',
  7311. :issue => {
  7312. :project_id => '',
  7313. :tracker_id => '',
  7314. :status_id => '3',
  7315. :start_date => '2009-12-01',
  7316. :due_date => '2009-12-31'
  7317. }
  7318. }
  7319. )
  7320. end
  7321. issue = Issue.order('id DESC').first
  7322. assert_equal 1, issue.journals.size
  7323. journal = issue.journals.first
  7324. assert_equal 'Copying one issue', journal.notes
  7325. end
  7326. def test_bulk_copy_should_allow_not_copying_the_attachments
  7327. attachment_count = Issue.find(3).attachments.size
  7328. assert attachment_count > 0
  7329. @request.session[:user_id] = 2
  7330. assert_difference 'Issue.count', 1 do
  7331. assert_no_difference 'Attachment.count' do
  7332. post(
  7333. :bulk_update,
  7334. :params => {
  7335. :ids => [3],
  7336. :copy => '1',
  7337. :copy_attachments => '0',
  7338. :issue => {
  7339. :project_id => ''
  7340. }
  7341. }
  7342. )
  7343. end
  7344. end
  7345. end
  7346. def test_bulk_copy_should_allow_copying_the_attachments
  7347. attachment_count = Issue.find(3).attachments.size
  7348. assert attachment_count > 0
  7349. @request.session[:user_id] = 2
  7350. assert_difference 'Issue.count', 1 do
  7351. assert_difference 'Attachment.count', attachment_count do
  7352. post(
  7353. :bulk_update,
  7354. :params => {
  7355. :ids => [3],
  7356. :copy => '1',
  7357. :copy_attachments => '1',
  7358. :issue => {
  7359. :project_id => ''
  7360. }
  7361. }
  7362. )
  7363. end
  7364. end
  7365. end
  7366. def test_bulk_copy_should_add_relations_with_copied_issues
  7367. @request.session[:user_id] = 2
  7368. assert_difference 'Issue.count', 2 do
  7369. assert_difference 'IssueRelation.count', 2 do
  7370. post(
  7371. :bulk_update,
  7372. :params => {
  7373. :ids => [1, 3],
  7374. :copy => '1',
  7375. :link_copy => '1',
  7376. :issue => {
  7377. :project_id => '1'
  7378. }
  7379. }
  7380. )
  7381. end
  7382. end
  7383. end
  7384. def test_bulk_copy_should_allow_not_copying_the_subtasks
  7385. issue = Issue.generate_with_descendants!
  7386. @request.session[:user_id] = 2
  7387. assert_difference 'Issue.count', 1 do
  7388. post(
  7389. :bulk_update,
  7390. :params => {
  7391. :ids => [issue.id],
  7392. :copy => '1',
  7393. :copy_subtasks => '0',
  7394. :issue => {
  7395. :project_id => ''
  7396. }
  7397. }
  7398. )
  7399. end
  7400. end
  7401. test "bulk copy should allow copying the subtasks" do
  7402. issue = Issue.generate_with_descendants!
  7403. count = issue.descendants.count
  7404. @request.session[:user_id] = 2
  7405. assert_difference 'Issue.count', count + 1 do
  7406. post(
  7407. :bulk_update,
  7408. :params => {
  7409. :ids => [issue.id],
  7410. :copy => '1',
  7411. :copy_subtasks => '1',
  7412. :issue => {
  7413. :project_id => ''
  7414. }
  7415. }
  7416. )
  7417. end
  7418. copy = Issue.where(:parent_id => nil).order("id DESC").first
  7419. assert_equal count, copy.descendants.count
  7420. end
  7421. test "issue bulk copy copy watcher" do
  7422. issue = Issue.find(1)
  7423. Watcher.create!(:watchable => issue, :user => User.find(3))
  7424. Watcher.create!(:watchable => issue, :user => Group.find(10))
  7425. @request.session[:user_id] = 2
  7426. assert_difference 'Issue.count' do
  7427. post(
  7428. :bulk_update,
  7429. :params => {
  7430. :ids => [1],
  7431. :copy => '1',
  7432. :copy_watchers => '1',
  7433. :issue => {
  7434. :project_id => ''
  7435. }
  7436. }
  7437. )
  7438. end
  7439. copy = Issue.order(:id => :desc).first
  7440. assert_equal 2, copy.watchers.count
  7441. assert_equal [3, 10], copy.watcher_user_ids.sort
  7442. end
  7443. def test_bulk_copy_should_not_copy_selected_subtasks_twice
  7444. issue = Issue.generate_with_descendants!
  7445. count = issue.descendants.count
  7446. @request.session[:user_id] = 2
  7447. assert_difference 'Issue.count', count + 1 do
  7448. post(
  7449. :bulk_update,
  7450. :params => {
  7451. :ids => issue.self_and_descendants.map(&:id),
  7452. :copy => '1',
  7453. :copy_subtasks => '1',
  7454. :issue => {
  7455. :project_id => ''
  7456. }
  7457. }
  7458. )
  7459. end
  7460. copy = Issue.where(:parent_id => nil).order("id DESC").first
  7461. assert_equal count, copy.descendants.count
  7462. end
  7463. def test_bulk_copy_to_another_project_should_follow_when_needed
  7464. @request.session[:user_id] = 2
  7465. post(
  7466. :bulk_update,
  7467. :params => {
  7468. :ids => [1],
  7469. :copy => '1',
  7470. :issue => {
  7471. :project_id => 2
  7472. },
  7473. :follow => '1'
  7474. }
  7475. )
  7476. issue = Issue.order('id DESC').first
  7477. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
  7478. end
  7479. def test_bulk_copy_with_all_failures_should_display_errors
  7480. @request.session[:user_id] = 2
  7481. post(
  7482. :bulk_update,
  7483. :params => {
  7484. :ids => [1, 2],
  7485. :copy => '1',
  7486. :issue => {
  7487. :start_date => 'foo'
  7488. }
  7489. }
  7490. )
  7491. assert_response :success
  7492. end
  7493. def test_destroy_issue_with_no_time_entries_should_delete_the_issues
  7494. set_tmp_attachments_directory
  7495. assert_nil TimeEntry.find_by_issue_id(2)
  7496. @request.session[:user_id] = 2
  7497. assert_difference 'Issue.count', -1 do
  7498. delete(:destroy, :params => {:id => 2})
  7499. end
  7500. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7501. assert_equal 'Successful deletion.', flash[:notice]
  7502. assert_nil Issue.find_by_id(2)
  7503. end
  7504. def test_destroy_issues_with_time_entries_should_show_the_reassign_form
  7505. set_tmp_attachments_directory
  7506. @request.session[:user_id] = 2
  7507. with_settings :timelog_required_fields => [] do
  7508. assert_no_difference 'Issue.count' do
  7509. delete(
  7510. :destroy,
  7511. :params => {
  7512. :ids => [1, 3]
  7513. }
  7514. )
  7515. end
  7516. end
  7517. assert_response :success
  7518. assert_select 'form' do
  7519. assert_select 'input[name=_method][value=delete]'
  7520. assert_select 'input[name=todo][value=destroy]'
  7521. assert_select 'input[name=todo][value=nullify]'
  7522. assert_select 'input[name=todo][value=reassign]'
  7523. end
  7524. end
  7525. def test_destroy_issues_with_time_entries_should_not_show_the_nullify_option_when_issue_is_required_for_time_entries
  7526. set_tmp_attachments_directory
  7527. with_settings :timelog_required_fields => ['issue_id'] do
  7528. @request.session[:user_id] = 2
  7529. assert_no_difference 'Issue.count' do
  7530. delete(
  7531. :destroy,
  7532. :params => {
  7533. :ids => [1, 3]
  7534. }
  7535. )
  7536. end
  7537. assert_response :success
  7538. assert_select 'form' do
  7539. assert_select 'input[name=_method][value=delete]'
  7540. assert_select 'input[name=todo][value=destroy]'
  7541. assert_select 'input[name=todo][value=nullify]', 0
  7542. assert_select 'input[name=todo][value=reassign]'
  7543. end
  7544. end
  7545. end
  7546. def test_destroy_issues_with_time_entries_should_show_hours_on_issues_and_descendants
  7547. parent = Issue.generate_with_child!
  7548. TimeEntry.generate!(:issue => parent)
  7549. TimeEntry.generate!(:issue => parent.children.first)
  7550. leaf = Issue.generate!
  7551. TimeEntry.generate!(:issue => leaf)
  7552. @request.session[:user_id] = 2
  7553. delete(
  7554. :destroy,
  7555. :params => {
  7556. :ids => [parent.id, leaf.id]
  7557. }
  7558. )
  7559. assert_response :success
  7560. assert_select 'p', :text => /3\.00 hours were reported/
  7561. end
  7562. def test_destroy_issues_and_destroy_time_entries
  7563. set_tmp_attachments_directory
  7564. @request.session[:user_id] = 2
  7565. assert_difference 'Issue.count', -2 do
  7566. assert_difference 'TimeEntry.count', -3 do
  7567. delete(
  7568. :destroy,
  7569. :params => {
  7570. :ids => [1, 3],
  7571. :todo => 'destroy'
  7572. }
  7573. )
  7574. end
  7575. end
  7576. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7577. assert_equal 'Successful deletion.', flash[:notice]
  7578. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7579. assert_nil TimeEntry.find_by_id([1, 2])
  7580. end
  7581. def test_destroy_issues_and_assign_time_entries_to_project
  7582. set_tmp_attachments_directory
  7583. @request.session[:user_id] = 2
  7584. with_settings :timelog_required_fields => [] do
  7585. assert_difference 'Issue.count', -2 do
  7586. assert_no_difference 'TimeEntry.count' do
  7587. delete(
  7588. :destroy,
  7589. :params => {
  7590. :ids => [1, 3],
  7591. :todo => 'nullify'
  7592. }
  7593. )
  7594. end
  7595. end
  7596. end
  7597. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7598. assert_equal 'Successful deletion.', flash[:notice]
  7599. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7600. assert_nil TimeEntry.find(1).issue_id
  7601. assert_nil TimeEntry.find(2).issue_id
  7602. end
  7603. def test_destroy_issues_and_reassign_time_entries_to_another_issue
  7604. set_tmp_attachments_directory
  7605. @request.session[:user_id] = 2
  7606. assert_difference 'Issue.count', -2 do
  7607. assert_no_difference 'TimeEntry.count' do
  7608. delete(
  7609. :destroy,
  7610. :params => {
  7611. :ids => [1, 3],
  7612. :todo => 'reassign',
  7613. :reassign_to_id => 2
  7614. }
  7615. )
  7616. end
  7617. end
  7618. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7619. assert_equal 'Successful deletion.', flash[:notice]
  7620. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7621. assert_equal 2, TimeEntry.find(1).issue_id
  7622. assert_equal 2, TimeEntry.find(2).issue_id
  7623. end
  7624. def test_destroy_issues_with_time_entries_should_reassign_time_entries_of_issues_and_descendants
  7625. parent = Issue.generate_with_child!
  7626. TimeEntry.generate!(:issue => parent)
  7627. TimeEntry.generate!(:issue => parent.children.first)
  7628. leaf = Issue.generate!
  7629. TimeEntry.generate!(:issue => leaf)
  7630. target = Issue.generate!
  7631. @request.session[:user_id] = 2
  7632. assert_difference 'Issue.count', -3 do
  7633. assert_no_difference 'TimeEntry.count' do
  7634. delete(
  7635. :destroy,
  7636. :params => {
  7637. :ids => [parent.id, leaf.id],
  7638. :todo => 'reassign',
  7639. :reassign_to_id => target.id
  7640. }
  7641. )
  7642. assert_response :found
  7643. assert_equal 'Successful deletion.', flash[:notice]
  7644. end
  7645. end
  7646. assert_equal 3, target.time_entries.count
  7647. end
  7648. def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
  7649. set_tmp_attachments_directory
  7650. @request.session[:user_id] = 2
  7651. assert_no_difference 'Issue.count' do
  7652. assert_no_difference 'TimeEntry.count' do
  7653. # try to reassign time to an issue of another project
  7654. delete(
  7655. :destroy,
  7656. :params => {
  7657. :ids => [1, 3],
  7658. :todo => 'reassign',
  7659. :reassign_to_id => 4
  7660. }
  7661. )
  7662. end
  7663. end
  7664. assert_response :success
  7665. end
  7666. def test_destroy_issues_and_reassign_time_entries_to_an_issue_to_delete_should_fail
  7667. set_tmp_attachments_directory
  7668. @request.session[:user_id] = 2
  7669. assert_no_difference 'Issue.count' do
  7670. assert_no_difference 'TimeEntry.count' do
  7671. delete(
  7672. :destroy,
  7673. :params => {
  7674. :ids => [1, 3],
  7675. :todo => 'reassign',
  7676. :reassign_to_id => 3
  7677. }
  7678. )
  7679. end
  7680. end
  7681. assert_response :success
  7682. assert_select '#flash_error', :text => I18n.t(:error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted)
  7683. end
  7684. def test_destroy_issues_and_nullify_time_entries_should_fail_when_issue_is_required_for_time_entries
  7685. set_tmp_attachments_directory
  7686. @request.session[:user_id] = 2
  7687. with_settings :timelog_required_fields => ['issue_id'] do
  7688. assert_no_difference 'Issue.count' do
  7689. assert_no_difference 'TimeEntry.count' do
  7690. delete(
  7691. :destroy,
  7692. :params => {
  7693. :ids => [1, 3],
  7694. :todo => 'nullify'
  7695. }
  7696. )
  7697. end
  7698. end
  7699. end
  7700. assert_response :success
  7701. assert_select '#flash_error', :text => 'Issue cannot be blank'
  7702. end
  7703. def test_destroy_issues_from_different_projects
  7704. set_tmp_attachments_directory
  7705. @request.session[:user_id] = 2
  7706. assert_difference 'Issue.count', -3 do
  7707. delete(
  7708. :destroy,
  7709. :params => {
  7710. :ids => [1, 2, 6],
  7711. :todo => 'destroy'
  7712. }
  7713. )
  7714. end
  7715. assert_redirected_to :controller => 'issues', :action => 'index'
  7716. assert_equal 'Successful deletion.', flash[:notice]
  7717. assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
  7718. end
  7719. def test_destroy_child_issue
  7720. parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
  7721. child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
  7722. assert child.is_descendant_of?(parent.reload)
  7723. @request.session[:user_id] = 2
  7724. assert_difference 'Issue.count', -1 do
  7725. delete :destroy, :params => {:id => child.id}
  7726. end
  7727. assert_response :found
  7728. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7729. parent.reload
  7730. assert_equal 2, parent.journals.count
  7731. get :show, :params => {:id => parent.id}
  7732. assert_response :success
  7733. assert_select 'div#tab-content-history' do
  7734. assert_select 'div[id=?]', "change-#{parent.journals.last.id}" do
  7735. assert_select 'ul.details', :text => "Subtask deleted (##{child.id})"
  7736. end
  7737. end
  7738. end
  7739. def test_destroy_parent_and_child_issues
  7740. parent = Issue.create!(:project_id => 1, :author_id => 1,
  7741. :tracker_id => 1, :subject => 'Parent Issue')
  7742. child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1,
  7743. :subject => 'Child Issue', :parent_issue_id => parent.id)
  7744. assert child.is_descendant_of?(parent.reload)
  7745. @request.session[:user_id] = 2
  7746. assert_difference 'Issue.count', -2 do
  7747. delete(
  7748. :destroy,
  7749. :params => {
  7750. :ids => [parent.id, child.id],
  7751. :todo => 'destroy'
  7752. }
  7753. )
  7754. end
  7755. assert_response :found
  7756. assert_equal 'Successful deletion.', flash[:notice]
  7757. end
  7758. def test_destroy_invalid_should_respond_with_404
  7759. @request.session[:user_id] = 2
  7760. assert_no_difference 'Issue.count' do
  7761. delete(:destroy, :params => {:id => 999})
  7762. end
  7763. assert_response :not_found
  7764. end
  7765. def test_destroy_with_permission_on_tracker_should_be_allowed
  7766. role = Role.find(1)
  7767. role.set_permission_trackers :delete_issues, [1]
  7768. role.save!
  7769. issue = Issue.generate!(:project_id => 1, :tracker_id => 1)
  7770. @request.session[:user_id] = 2
  7771. assert_difference 'Issue.count', -1 do
  7772. delete(:destroy, :params => {:id => issue.id})
  7773. end
  7774. assert_response :found
  7775. assert_equal 'Successful deletion.', flash[:notice]
  7776. end
  7777. def test_destroy_without_permission_on_tracker_should_be_denied
  7778. role = Role.find(1)
  7779. role.set_permission_trackers :delete_issues, [2]
  7780. role.save!
  7781. issue = Issue.generate!(:project_id => 1, :tracker_id => 1)
  7782. @request.session[:user_id] = 2
  7783. assert_no_difference 'Issue.count' do
  7784. delete(:destroy, :params => {:id => issue.id})
  7785. end
  7786. assert_response :forbidden
  7787. end
  7788. def test_default_search_scope
  7789. get :index
  7790. assert_select 'div#quick-search form' do
  7791. assert_select 'input[name=issues][value="1"][type=hidden]'
  7792. end
  7793. end
  7794. def setup_user_with_copy_but_not_add_permission
  7795. Role.all.each {|r| r.remove_permission! :add_issues}
  7796. Role.find_by_name('Manager').add_permission! :add_issues
  7797. user = User.generate!
  7798. User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
  7799. User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
  7800. user
  7801. end
  7802. def test_cancel_edit_link_for_issue_show_action_should_have_onclick_action
  7803. @request.session[:user_id] = 1
  7804. get(:show, :params => {:id => 1})
  7805. assert_response :success
  7806. assert_select 'a[href=?][onclick=?]', "/issues/1", "$('#update').hide(); return false;", :text => 'Cancel'
  7807. end
  7808. def test_cancel_edit_link_for_issue_edit_action_should_not_have_onclick_action
  7809. @request.session[:user_id] = 1
  7810. get(:edit, :params => {:id => 1})
  7811. assert_response :success
  7812. assert_select 'a[href=?][onclick=?]', "/issues/1", "", :text => 'Cancel'
  7813. end
  7814. def test_show_should_display_author_gravatar_only_when_not_assigned
  7815. issue = Issue.find(1)
  7816. assert_nil issue.assigned_to_id
  7817. @request.session[:user_id] = 1
  7818. with_settings :gravatar_enabled => '1' do
  7819. get :show, :params => {:id => issue.id}
  7820. assert_select 'div.gravatar-with-child' do
  7821. assert_select 'img.gravatar', 1
  7822. end
  7823. end
  7824. end
  7825. def test_show_should_display_author_and_assignee_gravatars_when_assigned
  7826. issue = Issue.find(1)
  7827. issue.assigned_to_id = 2
  7828. issue.save!
  7829. @request.session[:user_id] = 1
  7830. with_settings :gravatar_enabled => '1' do
  7831. get :show, :params => {:id => issue.id}
  7832. assert_select 'div.gravatar-with-child' do
  7833. assert_select 'img.gravatar', 2
  7834. assert_select 'img.gravatar-child', 1
  7835. end
  7836. end
  7837. end
  7838. def test_show_should_be_able_to_link_to_another_journal_attachment_of_the_same_issue
  7839. @request.session[:user_id] = 1
  7840. issue = Issue.find(2)
  7841. attachment = issue.journals.first.attachments.first
  7842. issue.init_journal(User.first, "attachment:#{attachment.filename}")
  7843. issue.save!
  7844. issue.reload
  7845. get :show, params: { id: issue.id }
  7846. assert_select "div#history div#journal-#{issue.journals.last.id}-notes" do
  7847. assert_select "a[href='/attachments/#{attachment.id}']", :text => 'source.rb'
  7848. end
  7849. end
  7850. def test_show_with_thumbnail_macro_should_be_able_to_fetch_image_of_different_journal
  7851. @request.session[:user_id] = 1
  7852. issue = Issue.find(2)
  7853. attachment = Attachment.generate!(filename: 'foo.png', digest: Redmine::Utils.random_hex(32))
  7854. attachment.update(container: issue)
  7855. issue.init_journal(User.first, "{{thumbnail(#{attachment.filename})}}")
  7856. issue.save!
  7857. issue.reload
  7858. get :show, params: { id: issue.id }
  7859. assert_select "div#history div#journal-#{issue.journals.last.id}-notes" do
  7860. assert_select "a.thumbnail[title=?][href='/attachments/#{attachment.id}']", 'foo.png'
  7861. end
  7862. end
  7863. def test_index_should_retrieve_default_query
  7864. query = IssueQuery.find(4)
  7865. IssueQuery.stubs(:default).returns query
  7866. [nil, 1].each do |user_id|
  7867. @request.session[:user_id] = user_id
  7868. get :index
  7869. assert_select 'h2', text: query.name
  7870. get :index, params: { project_id: 1 }
  7871. assert_select 'h2', text: query.name
  7872. end
  7873. end
  7874. def test_index_should_ignore_default_query_with_without_default
  7875. query = IssueQuery.find(4)
  7876. IssueQuery.stubs(:default).returns query
  7877. [nil, 1].each do |user_id|
  7878. @request.session[:user_id] = user_id
  7879. get :index, params: { set_filter: '1', without_default: '1' }
  7880. assert_select 'h2', text: I18n.t(:label_issue_plural)
  7881. get :index, params: { project_id: 1, set_filter: '1', without_default: '1' }
  7882. assert_select 'h2', text: I18n.t(:label_issue_plural)
  7883. end
  7884. end
  7885. def test_index_should_ignore_default_query_with_session_query
  7886. query = IssueQuery.find 4
  7887. IssueQuery.stubs(:default).returns query
  7888. session_query = IssueQuery.find 1
  7889. @request.session[:issue_query] = { id: 1, project_id: 1}
  7890. @request.session[:user_id] = 1
  7891. get :index, params: { project_id: '1' }
  7892. assert_select 'h2', text: session_query.name
  7893. end
  7894. def test_index_global_should_ignore_default_query_with_session_query
  7895. query = IssueQuery.find 4
  7896. IssueQuery.stubs(:default).returns query
  7897. session_query = IssueQuery.find 5
  7898. @request.session[:issue_query] = { id: 5, project_id: nil}
  7899. @request.session[:user_id] = 1
  7900. get :index
  7901. assert_select 'h2', text: session_query.name
  7902. end
  7903. def test_index_should_use_default_query_with_invalid_session_query
  7904. query = IssueQuery.find 4
  7905. IssueQuery.stubs(:default).returns query
  7906. @request.session[:issue_query] = { id: 1, project_id: 1}
  7907. @request.session[:user_id] = 1
  7908. get :index
  7909. assert_select 'h2', text: query.name
  7910. end
  7911. def test_index_should_not_load_default_query_for_api_request
  7912. query = IssueQuery.find 4
  7913. IssueQuery.stubs(:default).returns query
  7914. @request.session[:user_id] = 1
  7915. get :index, params: { format: 'json' }
  7916. assert results = JSON.parse(@response.body)['issues']
  7917. # query filters for tracker_id == 3
  7918. assert results.detect{ |i| i['tracker_id'] != 3 }
  7919. end
  7920. def test_index_should_ignore_user_default_query_if_it_is_invisible
  7921. query = IssueQuery.find(4)
  7922. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7923. query.save!
  7924. # If visible default query
  7925. @request.session[:user_id] = 2
  7926. @request.session[:issue_query] = nil
  7927. User.find(2).pref.update(default_issue_query: query.id)
  7928. get :index
  7929. assert_select 'h2', text: query.name
  7930. # If invisible default query
  7931. @request.session[:user_id] = 3
  7932. @request.session[:issue_query] = nil
  7933. User.find(3).pref.update(default_issue_query: query.id)
  7934. get :index
  7935. assert_select 'h2', text: 'Issues'
  7936. end
  7937. def test_index_should_ignore_project_default_query_if_it_is_not_public
  7938. query = IssueQuery.find(1)
  7939. query.project.update(default_issue_query: query)
  7940. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7941. query.save!
  7942. [User.find(1), User.find(2)].each do |user|
  7943. @request.session[:user_id] = user.id
  7944. @request.session[:issue_query] = nil
  7945. get :index, params: { project_id: query.project.id }
  7946. assert_select 'h2', text: 'Issues'
  7947. end
  7948. end
  7949. def test_index_should_ignore_global_default_query_if_it_is_not_public
  7950. query = IssueQuery.find(1)
  7951. with_settings default_issue_query: query.id do
  7952. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7953. query.save!
  7954. [User.find(1), User.find(2)].each do |user|
  7955. @request.session[:user_id] = user.id
  7956. @request.session[:issue_query] = nil
  7957. get :index
  7958. assert_select 'h2', text: 'Issues'
  7959. end
  7960. end
  7961. end
  7962. def test_get_new_with_issue_field_five_percent_increments
  7963. with_settings :issue_done_ratio => 'issue_field', :issue_done_ratio_interval => 5 do
  7964. @request.session[:user_id] = 1
  7965. get :new
  7966. assert_response :success
  7967. assert_select 'select#issue_done_ratio' do
  7968. assert_select 'option', count: 21
  7969. assert_select 'option:nth-of-type(1)', text: '0 %'
  7970. assert_select 'option:nth-of-type(2)', text: '5 %'
  7971. assert_select 'option:nth-of-type(21)', text: '100 %'
  7972. end
  7973. end
  7974. end
  7975. end