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

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