Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

issues_controller_test.rb 257KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672
  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 404
  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 403
  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_estimated_hours_total
  1752. Issue.delete_all
  1753. Issue.generate!(:estimated_hours => '5:30')
  1754. Issue.generate!(:estimated_hours => '1:06')
  1755. get(:index, :params => {:t => %w(estimated_hours)})
  1756. assert_response :success
  1757. assert_select '.query-totals'
  1758. assert_select '.total-for-estimated-hours span.value', :text => '6:36'
  1759. assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]'
  1760. end
  1761. def test_index_with_grouped_query_and_estimated_hours_total
  1762. Issue.delete_all
  1763. Issue.generate!(:estimated_hours => '5:30', :category_id => 1)
  1764. Issue.generate!(:estimated_hours => '2:18', :category_id => 1)
  1765. Issue.generate!(:estimated_hours => '1:06', :category_id => 2)
  1766. Issue.generate!(:estimated_hours => '4:36')
  1767. get(
  1768. :index,
  1769. :params => {
  1770. :t => %w(estimated_hours),
  1771. :group_by => 'category'
  1772. }
  1773. )
  1774. assert_response :success
  1775. assert_select '.query-totals'
  1776. assert_select '.query-totals .total-for-estimated-hours span.value', :text => '13:30'
  1777. assert_select 'tr.group', :text => /Printing/ do
  1778. assert_select '.total-for-estimated-hours span.value', :text => '7:48'
  1779. end
  1780. assert_select 'tr.group', :text => /Recipes/ do
  1781. assert_select '.total-for-estimated-hours span.value', :text => '1:06'
  1782. end
  1783. assert_select 'tr.group', :text => /blank/ do
  1784. assert_select '.total-for-estimated-hours span.value', :text => '4:36'
  1785. end
  1786. end
  1787. def test_index_with_int_custom_field_total
  1788. field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
  1789. CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
  1790. CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
  1791. get(:index, :params => {:t => ["cf_#{field.id}"]})
  1792. assert_response :success
  1793. assert_select '.query-totals'
  1794. assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
  1795. end
  1796. def test_index_with_spent_time_total_should_sum_visible_spent_time_only
  1797. TimeEntry.delete_all
  1798. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3)
  1799. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4)
  1800. get :index, :params => {:t => ["spent_hours"]}
  1801. assert_response :success
  1802. assert_select ".total-for-spent-hours span.value", :text => '7:00'
  1803. Project.find(3).disable_module!(:time_tracking)
  1804. get :index, :params => {:t => ["spent_hours"]}
  1805. assert_response :success
  1806. assert_select ".total-for-spent-hours span.value", :text => '3:00'
  1807. end
  1808. def test_index_totals_should_default_to_settings
  1809. with_settings :issue_list_default_totals => ['estimated_hours'] do
  1810. get :index
  1811. assert_response :success
  1812. assert_select '.total-for-estimated-hours span.value'
  1813. assert_select '.query-totals>span', 1
  1814. end
  1815. end
  1816. def test_index_send_html_if_query_is_invalid
  1817. get(
  1818. :index,
  1819. :params => {
  1820. :f => ['start_date'],
  1821. :op => {
  1822. :start_date => '='
  1823. }
  1824. }
  1825. )
  1826. assert_equal 'text/html', @response.media_type
  1827. assert_select_error /Start date cannot be blank/i
  1828. end
  1829. def test_index_send_nothing_if_query_is_invalid
  1830. get(
  1831. :index,
  1832. :params => {
  1833. :f => ['start_date'],
  1834. :op => {
  1835. :start_date => '='
  1836. },
  1837. :format => 'csv'
  1838. }
  1839. )
  1840. assert_equal 'text/csv', @response.media_type
  1841. assert @response.body.blank?
  1842. end
  1843. def test_index_should_include_new_issue_link
  1844. @request.session[:user_id] = 2
  1845. get(:index, :params => {:project_id => 1})
  1846. assert_select(
  1847. '#content a.new-issue[href="/projects/ecookbook/issues/new"]',
  1848. :text => 'New issue'
  1849. )
  1850. end
  1851. def test_index_should_not_include_new_issue_link_for_project_without_trackers
  1852. Project.find(1).trackers.clear
  1853. @request.session[:user_id] = 2
  1854. get(:index, :params => {:project_id => 1})
  1855. assert_select '#content a.new-issue', 0
  1856. end
  1857. def test_index_should_not_include_new_issue_link_for_users_with_copy_issues_permission_only
  1858. role = Role.find(1)
  1859. role.remove_permission! :add_issues
  1860. role.add_permission! :copy_issues
  1861. @request.session[:user_id] = 2
  1862. get(:index, :params => {:project_id => 1})
  1863. assert_select '#content a.new-issue', 0
  1864. end
  1865. def test_index_without_project_should_include_new_issue_link
  1866. @request.session[:user_id] = 2
  1867. get :index
  1868. assert_select '#content a.new-issue[href="/issues/new"]', :text => 'New issue'
  1869. end
  1870. def test_index_should_show_setting_link_with_edit_project_permission
  1871. role = Role.find(1)
  1872. role.add_permission! :edit_project
  1873. @request.session[:user_id] = 2
  1874. get(:index, :params => {:project_id => 1})
  1875. assert_select '#content a.icon-settings[href="/projects/ecookbook/settings/issues"]', 1
  1876. end
  1877. def test_index_should_not_show_setting_link_without_edit_project_permission
  1878. role = Role.find(1)
  1879. role.remove_permission! :edit_project
  1880. @request.session[:user_id] = 2
  1881. get(:index, :params => {:project_id => 1})
  1882. assert_select '#content a.icon-settings[href="/projects/ecookbook/settings/issues"]', 0
  1883. end
  1884. def test_index_should_not_include_new_issue_tab_when_disabled
  1885. with_settings :new_item_menu_tab => '0' do
  1886. @request.session[:user_id] = 2
  1887. get(:index, :params => {:project_id => 1})
  1888. assert_select '#main-menu a.new-issue', 0
  1889. end
  1890. end
  1891. def test_index_should_include_new_issue_tab_when_enabled
  1892. with_settings :new_item_menu_tab => '1' do
  1893. @request.session[:user_id] = 2
  1894. get(:index, :params => {:project_id => 1})
  1895. assert_select(
  1896. '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]',
  1897. :text => 'New issue'
  1898. )
  1899. end
  1900. end
  1901. def test_new_should_have_new_issue_tab_as_current_menu_item
  1902. with_settings :new_item_menu_tab => '1' do
  1903. @request.session[:user_id] = 2
  1904. get(:new, :params => {:project_id => 1})
  1905. assert_select '#main-menu a.new-issue.selected'
  1906. end
  1907. end
  1908. def test_index_should_not_include_new_issue_tab_for_project_without_trackers
  1909. with_settings :new_item_menu_tab => '1' do
  1910. Project.find(1).trackers.clear
  1911. @request.session[:user_id] = 2
  1912. get(:index, :params => {:project_id => 1})
  1913. assert_select '#main-menu a.new-issue', 0
  1914. end
  1915. end
  1916. def test_index_should_not_include_new_issue_tab_for_users_with_copy_issues_permission_only
  1917. with_settings :new_item_menu_tab => '1' do
  1918. role = Role.find(1)
  1919. role.remove_permission! :add_issues
  1920. role.add_permission! :copy_issues
  1921. @request.session[:user_id] = 2
  1922. get(:index, :params => {:project_id => 1})
  1923. assert_select '#main-menu a.new-issue', 0
  1924. end
  1925. end
  1926. def test_index_should_respect_timespan_format
  1927. with_settings :timespan_format => 'minutes' do
  1928. get(
  1929. :index,
  1930. :params => {
  1931. :set_filter => 1,
  1932. :c => %w(estimated_hours total_estimated_hours spent_hours total_spent_hours)
  1933. }
  1934. )
  1935. assert_select 'table.issues tr#issue-1 td.estimated_hours', :text => '200:00'
  1936. assert_select 'table.issues tr#issue-1 td.total_estimated_hours', :text => '200:00'
  1937. assert_select 'table.issues tr#issue-1 td.spent_hours', :text => '154:15'
  1938. assert_select 'table.issues tr#issue-1 td.total_spent_hours', :text => '154:15'
  1939. end
  1940. end
  1941. def test_show_by_anonymous
  1942. get(:show, :params => {:id => 1})
  1943. assert_response :success
  1944. assert_select 'div.issue div.description', :text => /Unable to print recipes/
  1945. assert_select '#content>.contextual:first-child' do
  1946. assert_select 'a', {:count => 1, :text => 'Edit'}
  1947. assert_select 'a', {:count => 0, :text => 'Log time'}
  1948. assert_select 'a', {:count => 0, :text => 'Watch'}
  1949. assert_select 'a', {:count => 0, :text => 'Copy'}
  1950. assert_select 'div.drdn-items a', {:count => 1, :text => 'Copy link'}
  1951. assert_select 'div.drdn-items a', {:count => 0, :text => 'Delete issue'}
  1952. end
  1953. # anonymous role is allowed to add a note
  1954. assert_select 'form#issue-form' do
  1955. assert_select 'fieldset' do
  1956. assert_select 'legend', :text => 'Notes'
  1957. assert_select 'textarea[name=?]', 'issue[notes]'
  1958. end
  1959. end
  1960. assert_select 'title', :text => "Bug #1: Cannot print recipes - eCookbook - Redmine"
  1961. end
  1962. def test_show_by_manager
  1963. @request.session[:user_id] = 2
  1964. get(:show, :params => {:id => 1})
  1965. assert_select 'a', :text => /Quote/
  1966. assert_select '#content>.contextual:first-child' do
  1967. assert_select 'a', {:count => 1, :text => 'Edit'}
  1968. assert_select 'a', {:count => 1, :text => 'Log time'}
  1969. assert_select 'a', {:count => 1, :text => 'Watch'}
  1970. assert_select 'a', {:count => 1, :text => 'Copy'}
  1971. assert_select 'div.drdn-items a', {:count => 1, :text => 'Copy link'}
  1972. assert_select 'div.drdn-items a', {:count => 1, :text => 'Delete issue'}
  1973. end
  1974. assert_select 'form#issue-form' do
  1975. assert_select 'fieldset' do
  1976. assert_select 'legend', :text => 'Change properties'
  1977. assert_select 'input[name=?]', 'issue[subject]'
  1978. end
  1979. assert_select 'fieldset' do
  1980. assert_select 'legend', :text => 'Log time'
  1981. assert_select 'input[name=?]', 'time_entry[hours]'
  1982. end
  1983. assert_select 'fieldset' do
  1984. assert_select 'legend', :text => 'Notes'
  1985. assert_select 'textarea[name=?]', 'issue[notes]'
  1986. end
  1987. end
  1988. end
  1989. def test_show_should_display_update_form
  1990. @request.session[:user_id] = 2
  1991. get(:show, :params => {:id => 1})
  1992. assert_response :success
  1993. assert_select 'form#issue-form' do
  1994. assert_select 'input[name=?]', 'issue[is_private]'
  1995. assert_select 'select[name=?]', 'issue[project_id]'
  1996. assert_select 'select[name=?]', 'issue[tracker_id]'
  1997. assert_select 'input[name=?]', 'issue[subject]'
  1998. assert_select 'textarea[name=?]', 'issue[description]'
  1999. assert_select 'select[name=?]', 'issue[status_id]'
  2000. assert_select 'select[name=?]', 'issue[priority_id]'
  2001. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  2002. assert_select 'select[name=?]', 'issue[category_id]'
  2003. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  2004. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  2005. assert_select 'input[name=?]', 'issue[start_date]'
  2006. assert_select 'input[name=?]', 'issue[due_date]'
  2007. assert_select 'select[name=?]', 'issue[done_ratio]'
  2008. assert_select 'input[name=?]', 'issue[custom_field_values][2]'
  2009. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  2010. assert_select 'textarea[name=?]', 'issue[notes]'
  2011. end
  2012. end
  2013. def test_show_should_display_update_form_with_minimal_permissions
  2014. Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
  2015. WorkflowTransition.where(:role_id => 1).delete_all
  2016. @request.session[:user_id] = 2
  2017. get(:show, :params => {:id => 1})
  2018. assert_response :success
  2019. assert_select 'form#issue-form' do
  2020. assert_select 'input[name=?]', 'issue[is_private]', 0
  2021. assert_select 'select[name=?]', 'issue[project_id]', 0
  2022. assert_select 'select[name=?]', 'issue[tracker_id]', 0
  2023. assert_select 'input[name=?]', 'issue[subject]', 0
  2024. assert_select 'textarea[name=?]', 'issue[description]', 0
  2025. assert_select 'select[name=?]', 'issue[status_id]', 0
  2026. assert_select 'select[name=?]', 'issue[priority_id]', 0
  2027. assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
  2028. assert_select 'select[name=?]', 'issue[category_id]', 0
  2029. assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
  2030. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  2031. assert_select 'input[name=?]', 'issue[start_date]', 0
  2032. assert_select 'input[name=?]', 'issue[due_date]', 0
  2033. assert_select 'select[name=?]', 'issue[done_ratio]', 0
  2034. assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
  2035. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  2036. assert_select 'textarea[name=?]', 'issue[notes]'
  2037. end
  2038. end
  2039. def test_show_should_not_display_update_form_without_permissions
  2040. Role.find(1).update_attribute :permissions, [:view_issues]
  2041. @request.session[:user_id] = 2
  2042. get(:show, :params => {:id => 1})
  2043. assert_response :success
  2044. assert_select 'form#issue-form', 0
  2045. end
  2046. def test_update_form_should_not_display_inactive_enumerations
  2047. assert !IssuePriority.find(15).active?
  2048. @request.session[:user_id] = 2
  2049. get(:show, :params => {:id => 1})
  2050. assert_response :success
  2051. assert_select 'form#issue-form' do
  2052. assert_select 'select[name=?]', 'issue[priority_id]' do
  2053. assert_select 'option[value="4"]'
  2054. assert_select 'option[value="15"]', 0
  2055. end
  2056. end
  2057. end
  2058. def test_update_form_should_allow_attachment_upload
  2059. @request.session[:user_id] = 2
  2060. get(:show, :params => {:id => 1})
  2061. assert_select 'form#issue-form[method=post][enctype="multipart/form-data"]' do
  2062. assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
  2063. end
  2064. end
  2065. def test_update_form_should_render_assign_to_me_link_when_issue_can_be_assigned_to_the_current_user
  2066. @request.session[:user_id] = 1
  2067. get(
  2068. :show,
  2069. :params => {
  2070. :id => 10
  2071. }
  2072. )
  2073. assert_select 'form#issue-form #attributes' do
  2074. assert_select 'a[class=?][data-id=?]', 'assign-to-me-link', '1', 1
  2075. end
  2076. end
  2077. def test_update_form_should_not_render_assign_to_me_link_when_issue_cannot_be_assigned_to_the_current_user
  2078. @request.session[:user_id] = 1
  2079. get(
  2080. :show,
  2081. :params => {
  2082. :id => 2
  2083. }
  2084. )
  2085. assert_select 'form#issue-form #attributes' do
  2086. assert_select 'a[class=?]', 'assign-to-me-link', 0
  2087. end
  2088. end
  2089. def test_update_form_should_not_show_assign_to_me_link_when_issue_is_assigned_to_the_current_user
  2090. issue = Issue.find(10)
  2091. issue.assigned_to_id = 1
  2092. issue.save!
  2093. @request.session[:user_id] = 1
  2094. get(
  2095. :show,
  2096. :params => {
  2097. :id => 10
  2098. }
  2099. )
  2100. assert_select 'form#issue-form #attributes' do
  2101. assert_select 'a[class=?]', 'assign-to-me-link hidden', 1
  2102. end
  2103. end
  2104. def test_show_should_deny_anonymous_access_without_permission
  2105. Role.anonymous.remove_permission!(:view_issues)
  2106. get(:show, :params => {:id => 1})
  2107. assert_response :redirect
  2108. end
  2109. def test_show_should_deny_anonymous_access_to_private_issue
  2110. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2111. get(:show, :params => {:id => 1})
  2112. assert_response :redirect
  2113. end
  2114. def test_show_should_deny_non_member_access_without_permission
  2115. Role.non_member.remove_permission!(:view_issues)
  2116. @request.session[:user_id] = 9
  2117. get(:show, :params => {:id => 1})
  2118. assert_response 403
  2119. end
  2120. def test_show_should_deny_non_member_access_to_private_issue
  2121. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2122. @request.session[:user_id] = 9
  2123. get(:show, :params => {:id => 1})
  2124. assert_response 403
  2125. end
  2126. def test_show_should_deny_member_access_without_permission
  2127. Role.find(1).remove_permission!(:view_issues)
  2128. @request.session[:user_id] = 2
  2129. get(:show, :params => {:id => 1})
  2130. assert_response 403
  2131. end
  2132. def test_show_should_deny_member_access_to_private_issue_without_permission
  2133. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2134. @request.session[:user_id] = 3
  2135. get(:show, :params => {:id => 1})
  2136. assert_response 403
  2137. end
  2138. def test_show_should_allow_author_access_to_private_issue
  2139. Issue.where(:id => 1).update_all(["is_private = ?, author_id = 3", true])
  2140. @request.session[:user_id] = 3
  2141. get(:show, :params => {:id => 1})
  2142. assert_response :success
  2143. end
  2144. def test_show_should_allow_assignee_access_to_private_issue
  2145. Issue.where(:id => 1).update_all(["is_private = ?, assigned_to_id = 3", true])
  2146. @request.session[:user_id] = 3
  2147. get(:show, :params => {:id => 1})
  2148. assert_response :success
  2149. end
  2150. def test_show_should_allow_member_access_to_private_issue_with_permission
  2151. Issue.where(:id => 1).update_all(["is_private = ?", true])
  2152. User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
  2153. @request.session[:user_id] = 3
  2154. get(:show, :params => {:id => 1})
  2155. assert_response :success
  2156. end
  2157. def test_show_should_format_related_issues_dates
  2158. with_settings :date_format => '%d/%m/%Y' do
  2159. issue = Issue.generate!(:start_date => '2018-11-29', :due_date => '2018-12-01')
  2160. IssueRelation.
  2161. create!(
  2162. :issue_from => Issue.find(1), :issue_to => issue,
  2163. :relation_type => 'relates'
  2164. )
  2165. get(:show, :params => {:id => 1})
  2166. assert_response :success
  2167. assert_select '#relations td.start_date', :text => '29/11/2018'
  2168. assert_select '#relations td.due_date', :text => '01/12/2018'
  2169. end
  2170. end
  2171. def test_show_should_not_disclose_relations_to_invisible_issues
  2172. with_settings :cross_project_issue_relations => '1' do
  2173. IssueRelation.
  2174. create!(
  2175. :issue_from => Issue.find(1),
  2176. :issue_to => Issue.find(2),
  2177. :relation_type => 'relates'
  2178. )
  2179. # Relation to a private project issue
  2180. IssueRelation.
  2181. create!(
  2182. :issue_from => Issue.find(1),
  2183. :issue_to => Issue.find(4),
  2184. :relation_type => 'relates'
  2185. )
  2186. get(:show, :params => {:id => 1})
  2187. assert_response :success
  2188. assert_select 'div#relations' do
  2189. assert_select 'a', :text => /#2$/
  2190. assert_select 'a', :text => /#4$/, :count => 0
  2191. end
  2192. end
  2193. end
  2194. def test_show_should_list_subtasks
  2195. issue = Issue.
  2196. create!(
  2197. :project_id => 1, :author_id => 1, :tracker_id => 1,
  2198. :parent_issue_id => 1, :subject => 'Child Issue'
  2199. )
  2200. get(:show, :params => {:id => 1})
  2201. assert_response :success
  2202. assert_select 'div#issue_tree' do
  2203. assert_select 'td.subject', :text => /Child Issue/
  2204. end
  2205. assert_select 'div#tab-content-history' do
  2206. assert_select 'div[id=?]', "change-#{Issue.find(1).journals.last.id}" do
  2207. assert_select 'ul.details', :text => "Subtask ##{issue.id} added"
  2208. end
  2209. end
  2210. end
  2211. def test_show_should_show_subtasks_stats
  2212. @request.session[:user_id] = 1
  2213. child1 = Issue.generate!(parent_issue_id: 1, subject: 'Open child issue')
  2214. Issue.generate!(parent_issue_id: 1, subject: 'Closed child issue', status_id: 5)
  2215. Issue.generate!(parent_issue_id: child1.id, subject: 'Open child of child')
  2216. # Issue not visible for anonymous
  2217. Issue.generate!(parent_issue_id: 1, subject: 'Private child', project_id: 5)
  2218. get(:show, params: {:id => 1})
  2219. assert_response :success
  2220. assert_select 'div#issue_tree span.issues-stat' do
  2221. assert_select 'span.badge', text: '4'
  2222. assert_select 'span.open a', text: '3 open'
  2223. assert_equal CGI.unescape(css_select('span.open a').first.attr(:href)),
  2224. "/issues?parent_id=~1&set_filter=true&status_id=o"
  2225. assert_select 'span.closed a', text: '1 closed'
  2226. assert_equal CGI.unescape(css_select('span.closed a').first.attr(:href)),
  2227. "/issues?parent_id=~1&set_filter=true&status_id=c"
  2228. end
  2229. end
  2230. def test_show_subtasks_stats_should_not_link_if_issue_has_zero_open_or_closed_subtasks
  2231. child1 = Issue.generate!(parent_issue_id: 1, subject: 'Open child issue')
  2232. get(:show, params: {:id => 1})
  2233. assert_response :success
  2234. assert_select 'div#issue_tree span.issues-stat' do
  2235. assert_select 'span.open a', text: '1 open'
  2236. assert_equal CGI.unescape(css_select('span.open a').first.attr(:href)),
  2237. "/issues?parent_id=~1&set_filter=true&status_id=o"
  2238. assert_select 'span.closed', text: '0 closed'
  2239. assert_select 'span.closed a', 0
  2240. end
  2241. end
  2242. def test_show_should_not_show_subtasks_stats_if_subtasks_are_not_visible
  2243. # Issue not visible for anonymous
  2244. Issue.generate!(parent_issue_id: 1, subject: 'Private child', project_id: 5)
  2245. get(:show, params: {:id => 1})
  2246. assert_response :success
  2247. assert_select 'div#issue_tree span.issues-stat', 0
  2248. end
  2249. def test_show_should_list_parents
  2250. issue = Issue.
  2251. create!(
  2252. :project_id => 1, :author_id => 1,
  2253. :tracker_id => 1, :parent_issue_id => 1,
  2254. :subject => 'Child Issue'
  2255. )
  2256. get(:show, :params => {:id => issue.id})
  2257. assert_response :success
  2258. assert_select 'div.subject' do
  2259. assert_select 'h3', 'Child Issue'
  2260. assert_select 'a[href="/issues/1"]'
  2261. end
  2262. end
  2263. def test_show_should_not_display_prev_next_links_without_query_in_session
  2264. get(:show, :params => {:id => 1})
  2265. assert_response :success
  2266. assert_select 'div.next-prev-links', 0
  2267. end
  2268. def test_show_should_display_prev_next_links_with_query_in_session
  2269. @request.session[:issue_query] =
  2270. {
  2271. :filters => {
  2272. 'status_id' => {
  2273. :values => [''], :operator => 'o'
  2274. }
  2275. },
  2276. :project_id => nil,
  2277. :sort => [['id', 'asc']]
  2278. }
  2279. with_settings :display_subprojects_issues => '0' do
  2280. get(:show, :params => {:id => 3})
  2281. end
  2282. assert_response :success
  2283. count = Issue.open.visible.count
  2284. # Previous and next issues for all projects
  2285. assert_select 'div.next-prev-links' do
  2286. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2287. assert_select 'a[href="/issues/5"]', :text => /Next/
  2288. assert_select 'span.position', :text => "3 of #{count}"
  2289. end
  2290. end
  2291. def test_show_should_display_prev_next_links_with_saved_query_in_session
  2292. query =
  2293. IssueQuery.create!(
  2294. :name => 'test',
  2295. :visibility => IssueQuery::VISIBILITY_PUBLIC,
  2296. :user_id => 1,
  2297. :filters => {'status_id' => {:values => ['5'], :operator => '='}},
  2298. :sort_criteria => [['id', 'asc']]
  2299. )
  2300. @request.session[:issue_query] = {:id => query.id, :project_id => nil}
  2301. get(:show, :params => {:id => 11})
  2302. assert_response :success
  2303. # Previous and next issues for all projects
  2304. assert_select 'div.next-prev-links' do
  2305. assert_select 'a[href="/issues/8"]', :text => /Previous/
  2306. assert_select 'a[href="/issues/12"]', :text => /Next/
  2307. end
  2308. end
  2309. def test_show_should_display_prev_next_links_with_query_and_sort_on_association
  2310. @request.session[:issue_query] =
  2311. {
  2312. :filters => {
  2313. 'status_id' => {
  2314. :values => [''], :operator => 'o'
  2315. }
  2316. },
  2317. :project_id => nil
  2318. }
  2319. %w(project tracker status priority author assigned_to category fixed_version).
  2320. each do |assoc_sort|
  2321. @request.session[:issue_query][:sort] = [[assoc_sort, 'asc']]
  2322. get(:show, :params => {:id => 3})
  2323. assert_response :success, "Wrong response status for #{assoc_sort} sort"
  2324. assert_select 'div.next-prev-links' do
  2325. assert_select 'a', :text => /(Previous|Next)/
  2326. end
  2327. end
  2328. end
  2329. def test_show_should_display_prev_next_links_with_project_query_in_session
  2330. @request.session[:issue_query] =
  2331. {
  2332. :filters => {
  2333. 'status_id' => {:values => [''], :operator => 'o'}
  2334. },
  2335. :project_id => 1, :sort => [['id', 'asc']]
  2336. }
  2337. with_settings :display_subprojects_issues => '0' do
  2338. get(:show, :params => {:id => 3})
  2339. end
  2340. assert_response :success
  2341. # Previous and next issues inside project
  2342. assert_select 'div.next-prev-links' do
  2343. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2344. assert_select 'a[href="/issues/7"]', :text => /Next/
  2345. end
  2346. end
  2347. def test_show_should_not_display_prev_link_for_first_issue
  2348. @request.session[:issue_query] =
  2349. {
  2350. :filters => {
  2351. 'status_id' => {:values => [''], :operator => 'o'}
  2352. },
  2353. :project_id => 1, :sort => [['id', 'asc']]
  2354. }
  2355. with_settings :display_subprojects_issues => '0' do
  2356. get(:show, :params => {:id => 1})
  2357. end
  2358. assert_response :success
  2359. assert_select 'div.next-prev-links' do
  2360. assert_select 'a', :text => /Previous/, :count => 0
  2361. assert_select 'a[href="/issues/2"]', :text => /Next/
  2362. end
  2363. end
  2364. def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
  2365. @request.session[:issue_query] =
  2366. {
  2367. :filters => {
  2368. 'status_id' => {:values => [''], :operator => 'c'}
  2369. },
  2370. :project_id => 1,
  2371. :sort => [['id', 'asc']]
  2372. }
  2373. get(:show, :params => {:id => 1})
  2374. assert_response :success
  2375. assert_select 'a', :text => /Previous/, :count => 0
  2376. assert_select 'a', :text => /Next/, :count => 0
  2377. end
  2378. def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
  2379. cf = IssueCustomField.
  2380. create!(
  2381. :name => 'User',
  2382. :is_for_all => true,
  2383. :tracker_ids => [1, 2, 3],
  2384. :field_format => 'user'
  2385. )
  2386. CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
  2387. CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
  2388. CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
  2389. CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
  2390. query =
  2391. IssueQuery.create!(
  2392. :name => 'test',
  2393. :visibility => IssueQuery::VISIBILITY_PUBLIC,
  2394. :user_id => 1, :filters => {},
  2395. :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']]
  2396. )
  2397. @request.session[:issue_query] = {:id => query.id, :project_id => nil}
  2398. get(:show, :params => {:id => 3})
  2399. assert_response :success
  2400. assert_select 'div.next-prev-links' do
  2401. assert_select 'a[href="/issues/2"]', :text => /Previous/
  2402. assert_select 'a[href="/issues/1"]', :text => /Next/
  2403. end
  2404. end
  2405. def test_show_should_display_prev_next_links_when_request_has_previous_and_next_issue_ids_params
  2406. get(
  2407. :show,
  2408. :params => {
  2409. :id => 1,
  2410. :prev_issue_id => 1,
  2411. :next_issue_id => 3,
  2412. :issue_position => 2,
  2413. :issue_count => 4
  2414. }
  2415. )
  2416. assert_response :success
  2417. assert_select 'div.next-prev-links' do
  2418. assert_select 'a[href="/issues/1"]', :text => /Previous/
  2419. assert_select 'a[href="/issues/3"]', :text => /Next/
  2420. assert_select 'span.position', :text => "2 of 4"
  2421. end
  2422. end
  2423. def test_show_should_display_category_field_if_categories_are_defined
  2424. Issue.update_all :category_id => nil
  2425. get(:show, :params => {:id => 1})
  2426. assert_response :success
  2427. assert_select '.attributes .category'
  2428. end
  2429. def test_show_should_not_display_category_field_if_no_categories_are_defined
  2430. Project.find(1).issue_categories.delete_all
  2431. get(:show, :params => {:id => 1})
  2432. assert_response :success
  2433. assert_select 'table.attributes .category', 0
  2434. end
  2435. def test_show_should_display_link_to_the_assigned_user
  2436. get(:show, :params => {:id => 2})
  2437. assert_response :success
  2438. assert_select '.assigned-to' do
  2439. assert_select 'a[href="/users/3"]'
  2440. end
  2441. end
  2442. def test_show_should_display_link_to_the_assigned_group
  2443. Issue.find(2).update_attribute(:assigned_to_id, 10)
  2444. get(:show, :params => {:id => 2})
  2445. assert_response :success
  2446. assert_select '.assigned-to' do
  2447. assert_select 'a[href="/groups/10"]'
  2448. end
  2449. end
  2450. def test_show_should_display_visible_changesets_from_other_projects
  2451. project = Project.find(2)
  2452. issue = project.issues.first
  2453. issue.changeset_ids = [102]
  2454. issue.save!
  2455. # changesets from other projects should be displayed even if repository
  2456. # is disabled on issue's project
  2457. project.disable_module! :repository
  2458. @request.session[:user_id] = 2
  2459. get(
  2460. :issue_tab,
  2461. :params => {
  2462. :id => issue.id,
  2463. :name => 'changesets'
  2464. },
  2465. :xhr => true
  2466. )
  2467. assert_select 'a[href=?]', '/projects/ecookbook/repository/10/revisions/3'
  2468. assert_select 'div.changeset p', :text => /eCookbook - /
  2469. end
  2470. def test_show_should_display_watchers
  2471. @request.session[:user_id] = 2
  2472. issue = Issue.find(1)
  2473. issue.add_watcher User.find(2)
  2474. issue.add_watcher Group.find(10)
  2475. get(:show, :params => {:id => 1})
  2476. assert_select 'div#watchers ul' do
  2477. assert_select 'li.user-2' do
  2478. assert_select 'a[href="/users/2"]'
  2479. assert_select 'a[class*=delete]'
  2480. end
  2481. assert_select "li.user-10" do
  2482. assert_select 'a[href="/users/10"]', false
  2483. assert_select 'a[class*=delete]'
  2484. end
  2485. end
  2486. end
  2487. def test_show_should_display_watchers_with_gravatars
  2488. @request.session[:user_id] = 2
  2489. issue = Issue.find(1)
  2490. issue.add_watcher User.find(2)
  2491. issue.add_watcher Group.find(10)
  2492. with_settings :gravatar_enabled => '1' do
  2493. get(:show, :params => {:id => 1})
  2494. end
  2495. assert_select 'div#watchers ul' do
  2496. assert_select 'li.user-2' do
  2497. assert_select 'img.gravatar[title=?]', 'John Smith'
  2498. assert_select 'a[href="/users/2"]'
  2499. assert_select 'a[class*=delete]'
  2500. end
  2501. assert_select "li.user-10" do
  2502. assert_select 'img.gravatar[title=?]', 'A Team'
  2503. assert_select 'a[href="/groups/10"]'
  2504. assert_select 'a[class*=delete]'
  2505. end
  2506. end
  2507. end
  2508. def test_show_should_mark_invalid_watchers
  2509. @request.session[:user_id] = 2
  2510. issue = Issue.find(4)
  2511. issue.add_watcher User.find(4)
  2512. get :show, :params => {:id => issue.id}
  2513. assert_response :success
  2514. assert_select 'div#watchers ul' do
  2515. assert_select 'li.user-4' do
  2516. assert_select 'span.icon-warning[title=?]', l(:notice_invalid_watcher), text: l(:notice_invalid_watcher)
  2517. end
  2518. end
  2519. end
  2520. def test_show_with_thumbnails_enabled_should_display_thumbnails
  2521. skip unless convert_installed?
  2522. @request.session[:user_id] = 2
  2523. with_settings :thumbnails_enabled => '1' do
  2524. get(:show, :params => {:id => 14})
  2525. assert_response :success
  2526. end
  2527. assert_select 'div.thumbnails' do
  2528. assert_select 'a[href="/attachments/16"]' do
  2529. assert_select 'img[src="/attachments/thumbnail/16/200"]'
  2530. end
  2531. end
  2532. end
  2533. def test_show_with_thumbnails_disabled_should_not_display_thumbnails
  2534. @request.session[:user_id] = 2
  2535. with_settings :thumbnails_enabled => '0' do
  2536. get(:show, :params => {:id => 14})
  2537. assert_response :success
  2538. end
  2539. assert_select 'div.thumbnails', 0
  2540. end
  2541. def test_show_with_multi_custom_field
  2542. field = CustomField.find(1)
  2543. field.update_attribute :multiple, true
  2544. issue = Issue.find(1)
  2545. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  2546. issue.save!
  2547. get(:show, :params => {:id => 1})
  2548. assert_response :success
  2549. assert_select ".cf_1 .value", :text => 'MySQL, Oracle'
  2550. end
  2551. def test_show_with_full_width_layout_custom_field_should_show_field_under_description
  2552. field =
  2553. IssueCustomField.
  2554. create!(
  2555. :name => 'Long text',
  2556. :field_format => 'text', :full_width_layout => '1',
  2557. :tracker_ids => [1], :is_for_all => true
  2558. )
  2559. issue = Issue.find(1)
  2560. issue.custom_field_values = {field.id => 'This is a long text'}
  2561. issue.save!
  2562. get(:show, :params => {:id => 1})
  2563. assert_response :success
  2564. # long text custom field should not be render in the attributes div
  2565. assert_select "div.attributes div.attribute.cf_#{field.id} p strong", 0
  2566. assert_select "div.attributes div.attribute.cf_#{field.id} div.value", 0
  2567. # long text custom field should be render under description field
  2568. assert_select "div.description ~ div.attribute.cf_#{field.id} p strong", :text => 'Long text'
  2569. assert_select(
  2570. "div.description ~ div.attribute.cf_#{field.id} div.value",
  2571. :text => 'This is a long text'
  2572. )
  2573. end
  2574. def test_show_custom_fields_with_full_text_formatting_should_be_rendered_using_wiki_class
  2575. half_field =
  2576. IssueCustomField.
  2577. create!(
  2578. :name => 'Half width field', :field_format => 'text',
  2579. :tracker_ids => [1], :is_for_all => true, :text_formatting => 'full'
  2580. )
  2581. full_field =
  2582. IssueCustomField.
  2583. create!(
  2584. :name => 'Full width field',
  2585. :field_format => 'text', :full_width_layout => '1',
  2586. :tracker_ids => [1], :is_for_all => true, :text_formatting => 'full'
  2587. )
  2588. issue = Issue.find(1)
  2589. issue.custom_field_values =
  2590. {full_field.id => 'This is a long text',
  2591. half_field.id => 'This is a short text'}
  2592. issue.save!
  2593. get(:show, :params => {:id => 1})
  2594. assert_response :success
  2595. assert_select "div.attribute.cf_#{half_field.id} div.value div.wiki", 1
  2596. assert_select "div.attribute.cf_#{full_field.id} div.value div.wiki", 1
  2597. end
  2598. def test_show_with_multi_user_custom_field
  2599. field =
  2600. IssueCustomField.
  2601. create!(
  2602. :name => 'Multi user',
  2603. :field_format => 'user', :multiple => true,
  2604. :tracker_ids => [1], :is_for_all => true
  2605. )
  2606. issue = Issue.find(1)
  2607. issue.custom_field_values = {field.id => ['2', '3']}
  2608. issue.save!
  2609. get(:show, :params => {:id => 1})
  2610. assert_response :success
  2611. assert_select ".cf_#{field.id} .value", :text => 'Dave Lopper, John Smith' do
  2612. assert_select 'a', :text => 'Dave Lopper'
  2613. assert_select 'a', :text => 'John Smith'
  2614. end
  2615. end
  2616. def test_show_should_not_display_default_value_for_new_custom_field
  2617. prior = Issue.generate!
  2618. field =
  2619. IssueCustomField.
  2620. generate!(
  2621. :name => 'WithDefault', :field_format => 'string',
  2622. :default_value => 'DEFAULT'
  2623. )
  2624. after = Issue.generate!
  2625. get :show, :params => {:id => prior.id}
  2626. assert_response :success
  2627. assert_select ".cf_#{field.id} .value", :text => ''
  2628. get :show, :params => {:id => after.id}
  2629. assert_response :success
  2630. assert_select ".cf_#{field.id} .value", :text => 'DEFAULT'
  2631. end
  2632. def test_show_should_display_private_notes_with_permission_only
  2633. journal =
  2634. Journal.
  2635. create!(
  2636. :journalized => Issue.find(2),
  2637. :notes => 'Privates notes',
  2638. :private_notes => true,
  2639. :user_id => 1
  2640. )
  2641. @request.session[:user_id] = 2
  2642. get(:show, :params => {:id => 2})
  2643. assert_response :success
  2644. assert_select "#change-#{journal.id}", 1
  2645. Role.find(1).remove_permission! :view_private_notes
  2646. get(:show, :params => {:id => 2})
  2647. assert_response :success
  2648. assert_select "#change-#{journal.id}", 0
  2649. end
  2650. def test_show_should_display_private_notes_created_by_current_user
  2651. User.find(3).roles_for_project(Project.find(1)).each do |role|
  2652. role.remove_permission! :view_private_notes
  2653. end
  2654. visible =
  2655. Journal.
  2656. create!(
  2657. :journalized => Issue.find(2),
  2658. :notes => 'Private notes',
  2659. :private_notes => true, :user_id => 3
  2660. )
  2661. not_visible =
  2662. Journal.create!(
  2663. :journalized => Issue.find(2),
  2664. :notes => 'Private notes',
  2665. :private_notes => true, :user_id => 1
  2666. )
  2667. @request.session[:user_id] = 3
  2668. get(:show, :params => {:id => 2})
  2669. assert_response :success
  2670. assert_select "#change-#{visible.id}", 1
  2671. assert_select "#change-#{not_visible.id}", 0
  2672. end
  2673. def test_show_should_mark_notes_as_edited_only_for_edited_notes
  2674. get :show, :params => {:id => 1}
  2675. assert_response :success
  2676. journal = Journal.find(1)
  2677. journal_title = l(:label_time_by_author, :time => format_time(journal.updated_on), :author => journal.updated_by)
  2678. assert_select "#change-1 h4 span.update-info[title=?]", journal_title, :text => '· Edited'
  2679. assert_select "#change-2 h4 span.update-info", 0
  2680. end
  2681. def test_show_atom
  2682. with_settings :text_formatting => 'textile' do
  2683. get(
  2684. :show,
  2685. :params => {
  2686. :id => 2,
  2687. :format => 'atom'
  2688. }
  2689. )
  2690. assert_response :success
  2691. assert_equal 'application/atom+xml', response.media_type
  2692. # Inline image
  2693. assert_select(
  2694. 'content',
  2695. :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
  2696. )
  2697. end
  2698. end
  2699. def test_show_export_to_pdf
  2700. issue = Issue.find(3)
  2701. assert issue.relations.any? {|r| r.other_issue(issue).visible?}
  2702. get(
  2703. :show,
  2704. :params => {
  2705. :id => 3,
  2706. :format => 'pdf'
  2707. }
  2708. )
  2709. assert_response :success
  2710. assert_equal 'application/pdf', @response.media_type
  2711. assert @response.body.starts_with?('%PDF')
  2712. end
  2713. def test_export_to_pdf_with_utf8_u_fffd
  2714. issue = Issue.generate!(:subject => "�")
  2715. ["en", "zh", "zh-TW", "ja", "ko", "ar"].each do |lang|
  2716. with_settings :default_language => lang do
  2717. get(
  2718. :show,
  2719. :params => {
  2720. :id => issue.id,
  2721. :format => 'pdf'
  2722. }
  2723. )
  2724. assert_response :success
  2725. assert_equal 'application/pdf', @response.media_type
  2726. assert @response.body.starts_with?('%PDF')
  2727. end
  2728. end
  2729. end
  2730. def test_show_export_to_pdf_with_ancestors
  2731. issue = Issue.generate!(:project_id => 1, :author_id => 2,
  2732. :tracker_id => 1, :subject => 'child',
  2733. :parent_issue_id => 1)
  2734. get(
  2735. :show,
  2736. :params => {
  2737. :id => issue.id,
  2738. :format => 'pdf'
  2739. }
  2740. )
  2741. assert_response :success
  2742. assert_equal 'application/pdf', @response.media_type
  2743. assert @response.body.starts_with?('%PDF')
  2744. end
  2745. def test_show_export_to_pdf_with_descendants
  2746. c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2747. :subject => 'child', :parent_issue_id => 1)
  2748. c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2749. :subject => 'child', :parent_issue_id => 1)
  2750. c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1,
  2751. :subject => 'child', :parent_issue_id => c1.id)
  2752. get(
  2753. :show,
  2754. :params => {
  2755. :id => 1,
  2756. :format => 'pdf'
  2757. }
  2758. )
  2759. assert_response :success
  2760. assert_equal 'application/pdf', @response.media_type
  2761. assert @response.body.starts_with?('%PDF')
  2762. end
  2763. def test_show_export_to_pdf_with_journals
  2764. get(
  2765. :show,
  2766. :params => {
  2767. :id => 1,
  2768. :format => 'pdf'
  2769. }
  2770. )
  2771. assert_response :success
  2772. assert_equal 'application/pdf', @response.media_type
  2773. assert @response.body.starts_with?('%PDF')
  2774. end
  2775. def test_show_export_to_pdf_with_private_journal
  2776. Journal.create!(
  2777. :journalized => Issue.find(1),
  2778. :notes => 'Private notes',
  2779. :private_notes => true,
  2780. :user_id => 3
  2781. )
  2782. @request.session[:user_id] = 3
  2783. get(
  2784. :show,
  2785. :params => {
  2786. :id => 1,
  2787. :format => 'pdf'
  2788. }
  2789. )
  2790. assert_response :success
  2791. assert_equal 'application/pdf', @response.media_type
  2792. assert @response.body.starts_with?('%PDF')
  2793. end
  2794. def test_show_export_to_pdf_with_changesets
  2795. [[100], [100, 101], [100, 101, 102]].each do |cs|
  2796. issue1 = Issue.find(3)
  2797. issue1.changesets = Changeset.find(cs)
  2798. issue1.save!
  2799. issue = Issue.find(3)
  2800. assert_equal issue.changesets.count, cs.size
  2801. get(
  2802. :show,
  2803. :params => {
  2804. :id => 3,
  2805. :format => 'pdf'
  2806. }
  2807. )
  2808. assert_response :success
  2809. assert_equal 'application/pdf', @response.media_type
  2810. assert @response.body.starts_with?('%PDF')
  2811. end
  2812. end
  2813. def test_show_invalid_should_respond_with_404
  2814. get(:show, :params => {:id => 999})
  2815. assert_response 404
  2816. end
  2817. def test_show_on_active_project_should_display_edit_links
  2818. @request.session[:user_id] = 1
  2819. get(:show, :params => {:id => 1})
  2820. assert_response :success
  2821. assert_select 'a', :text => 'Edit'
  2822. assert_select 'a', :text => 'Delete issue'
  2823. end
  2824. def test_show_on_closed_project_should_not_display_edit_links
  2825. Issue.find(1).project.close
  2826. @request.session[:user_id] = 1
  2827. get(:show, :params => {:id => 1})
  2828. assert_response :success
  2829. assert_select 'a', :text => 'Edit', :count => 0
  2830. assert_select 'a', :text => 'Delete issue', :count => 0
  2831. end
  2832. def test_show_should_not_display_history_tabs_for_issue_without_journals
  2833. @request.session[:user_id] = 1
  2834. get :show, :params => {:id => 5}
  2835. assert_response :success
  2836. assert_select '#history div.tabs', 0
  2837. assert_select '#history p.nodata', :text => 'No data to display'
  2838. end
  2839. def test_show_display_only_all_and_notes_tabs_for_issue_with_notes_only
  2840. @request.session[:user_id] = 1
  2841. get :show, :params => {:id => 14}
  2842. assert_response :success
  2843. assert_select '#history' do
  2844. assert_select 'div.tabs ul a', 2
  2845. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2846. assert_select 'div.tabs a[id=?]', 'tab-notes', :text => 'Notes'
  2847. end
  2848. end
  2849. def test_show_display_only_all_and_history_tabs_for_issue_with_history_changes_only
  2850. journal = Journal.create!(:journalized => Issue.find(5), :user_id => 1)
  2851. detail =
  2852. JournalDetail.
  2853. create!(
  2854. :journal => journal, :property => 'attr',
  2855. :prop_key => 'description',
  2856. :old_value => 'Foo', :value => 'Bar'
  2857. )
  2858. @request.session[:user_id] = 1
  2859. get :show, :params => {:id => 5}
  2860. assert_response :success
  2861. assert_select '#history' do
  2862. assert_select 'div.tabs ul a', 2
  2863. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2864. assert_select 'div.tabs a[id=?]', 'tab-properties', :text => 'Property changes'
  2865. end
  2866. end
  2867. def test_show_display_all_notes_and_history_tabs_for_issue_with_notes_and_history_changes
  2868. journal = Journal.create!(:journalized => Issue.find(6), :user_id => 1)
  2869. @request.session[:user_id] = 1
  2870. get :show, :params => {:id => 6}
  2871. assert_response :success
  2872. assert_select '#history' do
  2873. assert_select 'div.tabs ul a', 3
  2874. assert_select 'div.tabs a[id=?]', 'tab-history', :text => 'History'
  2875. assert_select 'div.tabs a[id=?]', 'tab-notes', :text => 'Notes'
  2876. assert_select 'div.tabs a[id=?]', 'tab-properties', :text => 'Property changes'
  2877. end
  2878. end
  2879. def test_show_display_changesets_tab_for_issue_with_changesets
  2880. project = Project.find(2)
  2881. issue = Issue.find(9)
  2882. issue.changeset_ids = [102]
  2883. issue.save!
  2884. @request.session[:user_id] = 2
  2885. get :show, :params => {:id => issue.id}
  2886. assert_select '#history' do
  2887. assert_select 'div.tabs ul a', 1
  2888. assert_select 'div.tabs a[id=?]', 'tab-changesets', :text => 'Associated revisions'
  2889. end
  2890. end
  2891. def test_show_should_display_spent_time_tab_for_issue_with_time_entries
  2892. @request.session[:user_id] = 1
  2893. get :show, :params => {:id => 3}
  2894. assert_response :success
  2895. assert_select '#history' do
  2896. assert_select 'div.tabs ul a', 1
  2897. assert_select 'div.tabs a[id=?]', 'tab-time_entries', :text => 'Spent time'
  2898. end
  2899. get(
  2900. :issue_tab,
  2901. :params => {
  2902. :id => 3,
  2903. :name => 'time_entries'
  2904. },
  2905. :xhr => true
  2906. )
  2907. assert_response :success
  2908. assert_select 'div[id=?]', 'time-entry-3' do
  2909. assert_select 'a[title=?][href=?]', 'Edit', '/time_entries/3/edit'
  2910. assert_select 'a[title=?][href=?]', 'Delete', '/time_entries/3'
  2911. assert_select 'ul[class=?]', 'details', :text => /1.00 h/
  2912. end
  2913. end
  2914. def test_show_should_display_open_badge_for_open_issue
  2915. get :show, params: {id: 1}
  2916. assert_response :success
  2917. assert_select 'span.badge.badge-status-open', text: 'open'
  2918. end
  2919. def test_show_should_display_closed_badge_for_closed_issue
  2920. get :show, params: {id: 8}
  2921. assert_response :success
  2922. assert_select 'span.badge.badge-status-closed', text: 'closed'
  2923. end
  2924. def test_show_should_display_private_badge_for_private_issue
  2925. @request.session[:user_id] = 1
  2926. get :show, params: {id: 14}
  2927. assert_response :success
  2928. assert_select 'span.badge.badge-private', text: 'Private'
  2929. end
  2930. def test_show_should_not_display_edit_attachment_icon_for_user_without_edit_issue_permission_on_tracker
  2931. role = Role.find(2)
  2932. role.set_permission_trackers 'edit_issues', [2, 3]
  2933. role.save!
  2934. @request.session[:user_id] = 2
  2935. get :show, params: {id: 4}
  2936. assert_response :success
  2937. assert_select 'div.attachments .icon-edit', 0
  2938. end
  2939. def test_show_should_not_display_delete_attachment_icon_for_user_without_edit_issue_permission_on_tracker
  2940. role = Role.find(2)
  2941. role.set_permission_trackers 'edit_issues', [2, 3]
  2942. role.save!
  2943. @request.session[:user_id] = 2
  2944. get :show, params: {id: 4}
  2945. assert_response :success
  2946. assert_select 'div.attachments .icon-del', 0
  2947. end
  2948. def test_get_new
  2949. @request.session[:user_id] = 2
  2950. get(
  2951. :new,
  2952. :params => {
  2953. :project_id => 1,
  2954. :tracker_id => 1
  2955. }
  2956. )
  2957. assert_response :success
  2958. assert_select 'form#issue-form[action=?]', '/projects/ecookbook/issues'
  2959. assert_select 'form#issue-form' do
  2960. assert_select 'input[name=?]', 'issue[is_private]'
  2961. assert_select 'select[name=?]', 'issue[project_id]'
  2962. assert_select 'select[name=?]', 'issue[tracker_id]'
  2963. assert_select 'input[name=?]', 'issue[subject]'
  2964. assert_select 'textarea[name=?]', 'issue[description]'
  2965. assert_select 'select[name=?]', 'issue[status_id]'
  2966. assert_select 'select[name=?]', 'issue[priority_id]'
  2967. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  2968. assert_select 'select[name=?]', 'issue[category_id]'
  2969. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  2970. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  2971. assert_select 'input[name=?]', 'issue[start_date]'
  2972. assert_select 'input[name=?]', 'issue[due_date]'
  2973. assert_select 'select[name=?]', 'issue[done_ratio]'
  2974. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
  2975. assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
  2976. # Assert submit buttons
  2977. assert_select 'input[type=submit][name=?]', 'commit'
  2978. assert_select 'input[type=submit][name=?]', 'continue'
  2979. assert_select 'input[type=submit][name=?]', 'follow', 0
  2980. end
  2981. # Be sure we don't display inactive IssuePriorities
  2982. assert_not IssuePriority.find(15).active?
  2983. assert_select 'select[name=?]', 'issue[priority_id]' do
  2984. assert_select 'option[value="15"]', 0
  2985. end
  2986. end
  2987. def test_get_new_global_should_show_all_projects
  2988. @request.session[:user_id] = 1
  2989. get :new
  2990. assert_response :success
  2991. assert_select 'select[name=?]', 'issue[project_id]' do
  2992. assert_select 'option[value=?]', '1'
  2993. assert_select 'option[value=?]', '2'
  2994. end
  2995. end
  2996. def test_get_new_should_show_project_selector_for_project_with_subprojects
  2997. @request.session[:user_id] = 2
  2998. get(
  2999. :new,
  3000. :params => {
  3001. :project_id => 3,
  3002. :tracker_id => 1
  3003. }
  3004. )
  3005. assert_response :success
  3006. assert_select 'select[name="issue[project_id]"]' do
  3007. assert_select 'option', 3
  3008. assert_select 'option[value=?]', '1', :text => 'eCookbook'
  3009. assert_select 'option[value=?]', '5', :text => '  » Private child of eCookbook'
  3010. assert_select 'option[selected=selected][value=?]', '3', :text => '  » eCookbook Subproject 1'
  3011. # user_id 2 is not allowed to add issues on project_id 4 (it's not a member)
  3012. assert_select 'option[value=?]', '4', 0
  3013. end
  3014. end
  3015. def test_get_new_should_not_show_project_selector_for_project_without_subprojects
  3016. @request.session[:user_id] = 2
  3017. get(
  3018. :new,
  3019. :params => {
  3020. :project_id => 2,
  3021. :tracker_id => 1
  3022. }
  3023. )
  3024. assert_response :success
  3025. assert_select 'select[name="issue[project_id]"]', 0
  3026. end
  3027. def test_get_new_should_not_show_invalid_projects_when_issue_is_a_subtask
  3028. @request.session[:user_id] = 2
  3029. issue = Issue.find(1)
  3030. issue.parent_id = 3
  3031. issue.save
  3032. with_settings :cross_project_subtasks => 'tree' do
  3033. get(
  3034. :new,
  3035. :params => {
  3036. :project_id => 1,
  3037. :parent_issue_id => 1
  3038. }
  3039. )
  3040. end
  3041. assert_response :success
  3042. assert_select 'select[name="issue[project_id]"]' do
  3043. assert_select 'option', 3
  3044. # Onlinestore project should not be included
  3045. assert_select 'option[value=?]', '2', 0
  3046. end
  3047. end
  3048. def test_get_new_with_minimal_permissions
  3049. Role.find(1).update_attribute :permissions, [:add_issues]
  3050. WorkflowTransition.where(:role_id => 1).delete_all
  3051. @request.session[:user_id] = 2
  3052. get(
  3053. :new,
  3054. :params => {
  3055. :project_id => 1,
  3056. :tracker_id => 1
  3057. }
  3058. )
  3059. assert_response :success
  3060. assert_select 'form#issue-form' do
  3061. assert_select 'input[name=?]', 'issue[is_private]', 0
  3062. assert_select 'select[name=?]', 'issue[project_id]'
  3063. assert_select 'select[name=?]', 'issue[tracker_id]'
  3064. assert_select 'input[name=?]', 'issue[subject]'
  3065. assert_select 'textarea[name=?]', 'issue[description]'
  3066. assert_select 'select[name=?]', 'issue[status_id]'
  3067. assert_select 'select[name=?]', 'issue[priority_id]'
  3068. assert_select 'select[name=?]', 'issue[assigned_to_id]'
  3069. assert_select 'select[name=?]', 'issue[category_id]'
  3070. assert_select 'select[name=?]', 'issue[fixed_version_id]'
  3071. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  3072. assert_select 'input[name=?]', 'issue[start_date]'
  3073. assert_select 'input[name=?]', 'issue[due_date]'
  3074. assert_select 'select[name=?]', 'issue[done_ratio]'
  3075. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
  3076. assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
  3077. end
  3078. end
  3079. def test_new_without_project_id
  3080. @request.session[:user_id] = 2
  3081. get :new
  3082. assert_response :success
  3083. assert_select 'form#issue-form[action=?]', '/issues'
  3084. assert_select 'form#issue-form' do
  3085. assert_select 'select[name=?]', 'issue[project_id]'
  3086. end
  3087. end
  3088. def test_new_with_me_assigned_to_id
  3089. @request.session[:user_id] = 2
  3090. get(
  3091. :new,
  3092. :params => {
  3093. :issue => {:assigned_to_id => 'me'}
  3094. }
  3095. )
  3096. assert_response :success
  3097. assert_select 'select[name=?]', 'issue[assigned_to_id]' do
  3098. assert_select 'option[value="2"][selected=selected]'
  3099. end
  3100. end
  3101. def test_new_should_select_default_status
  3102. @request.session[:user_id] = 2
  3103. get(:new, :params => {:project_id => 1})
  3104. assert_response :success
  3105. assert_select 'select[name=?]', 'issue[status_id]' do
  3106. assert_select 'option[value="1"][selected=selected]'
  3107. end
  3108. assert_select 'input[name=was_default_status][value="1"]'
  3109. end
  3110. def test_new_should_propose_allowed_statuses
  3111. WorkflowTransition.delete_all
  3112. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3113. :old_status_id => 0, :new_status_id => 1)
  3114. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3115. :old_status_id => 0, :new_status_id => 3)
  3116. @request.session[:user_id] = 2
  3117. get(:new, :params => {:project_id => 1})
  3118. assert_response :success
  3119. assert_select 'select[name=?]', 'issue[status_id]' do
  3120. assert_select 'option[value="1"]'
  3121. assert_select 'option[value="3"]'
  3122. assert_select 'option', 2
  3123. assert_select 'option[value="1"][selected=selected]'
  3124. end
  3125. end
  3126. def test_new_should_propose_allowed_statuses_without_default_status_allowed
  3127. WorkflowTransition.delete_all
  3128. WorkflowTransition.create!(:tracker_id => 1, :role_id => 1,
  3129. :old_status_id => 0, :new_status_id => 2)
  3130. assert_equal 1, Tracker.find(1).default_status_id
  3131. @request.session[:user_id] = 2
  3132. get(:new, :params => {:project_id => 1})
  3133. assert_response :success
  3134. assert_select 'select[name=?]', 'issue[status_id]' do
  3135. assert_select 'option[value="2"]'
  3136. assert_select 'option', 1
  3137. assert_select 'option[value="2"][selected=selected]'
  3138. end
  3139. end
  3140. def test_new_should_propose_allowed_trackers
  3141. role = Role.find(1)
  3142. role.set_permission_trackers 'add_issues', [1, 3]
  3143. role.save!
  3144. @request.session[:user_id] = 2
  3145. get(:new, :params => {:project_id => 1})
  3146. assert_response :success
  3147. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3148. assert_select 'option', 2
  3149. assert_select 'option[value="1"]'
  3150. assert_select 'option[value="3"]'
  3151. end
  3152. end
  3153. def test_new_should_default_to_first_tracker
  3154. @request.session[:user_id] = 2
  3155. get(:new, :params => {:project_id => 1})
  3156. assert_response :success
  3157. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3158. assert_select 'option', 3
  3159. assert_select 'option[value="1"][selected=selected]'
  3160. end
  3161. end
  3162. def test_new_with_parent_issue_id_should_default_to_first_tracker_without_disabled_parent_field
  3163. tracker = Tracker.find(1)
  3164. tracker.core_fields -= ['parent_issue_id']
  3165. tracker.save!
  3166. @request.session[:user_id] = 2
  3167. get(
  3168. :new,
  3169. :params => {
  3170. :project_id => 1,
  3171. :issue => {
  3172. :parent_issue_id => 1
  3173. }
  3174. }
  3175. )
  3176. assert_response :success
  3177. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3178. assert_select 'option', 2
  3179. assert_select 'option[value="2"][selected=selected]'
  3180. assert_select 'option[value="1"]', 0
  3181. end
  3182. end
  3183. def test_new_without_allowed_trackers_should_respond_with_403
  3184. role = Role.find(1)
  3185. role.set_permission_trackers 'add_issues', []
  3186. role.save!
  3187. @request.session[:user_id] = 2
  3188. get(:new, :params => {:project_id => 1})
  3189. assert_response 403
  3190. end
  3191. def test_new_without_projects_should_respond_with_403
  3192. Project.delete_all
  3193. @request.session[:user_id] = 2
  3194. get :new
  3195. assert_response 403
  3196. assert_select_error /no projects/
  3197. end
  3198. def test_new_without_enabled_trackers_on_projects_should_respond_with_403
  3199. Project.all.each {|p| p.trackers.clear}
  3200. @request.session[:user_id] = 2
  3201. get :new
  3202. assert_response 403
  3203. assert_select_error /no projects/
  3204. end
  3205. def test_new_should_preselect_default_version
  3206. version = Version.generate!(:project_id => 1)
  3207. Project.find(1).update_attribute :default_version_id, version.id
  3208. @request.session[:user_id] = 2
  3209. get(:new, :params => {:project_id => 1})
  3210. assert_response :success
  3211. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  3212. assert_select 'option[value=?][selected=selected]', version.id.to_s
  3213. end
  3214. end
  3215. def test_get_new_with_list_custom_field
  3216. @request.session[:user_id] = 2
  3217. get(
  3218. :new,
  3219. :params => {
  3220. :project_id => 1,
  3221. :tracker_id => 1
  3222. }
  3223. )
  3224. assert_response :success
  3225. assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
  3226. assert_select 'option', 4
  3227. assert_select 'option[value=MySQL]', :text => 'MySQL'
  3228. end
  3229. end
  3230. def test_get_new_with_multi_custom_field
  3231. field = IssueCustomField.find(1)
  3232. field.update_attribute :multiple, true
  3233. @request.session[:user_id] = 2
  3234. get(
  3235. :new,
  3236. :params => {
  3237. :project_id => 1,
  3238. :tracker_id => 1
  3239. }
  3240. )
  3241. assert_response :success
  3242. assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
  3243. assert_select 'option', 3
  3244. assert_select 'option[value=MySQL]', :text => 'MySQL'
  3245. end
  3246. assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
  3247. end
  3248. def test_get_new_with_multi_user_custom_field
  3249. field =
  3250. IssueCustomField.
  3251. create!(
  3252. :name => 'Multi user', :field_format => 'user', :multiple => true,
  3253. :tracker_ids => [1], :is_for_all => true
  3254. )
  3255. @request.session[:user_id] = 2
  3256. get(
  3257. :new,
  3258. :params => {
  3259. :project_id => 1,
  3260. :tracker_id => 1
  3261. }
  3262. )
  3263. assert_response :success
  3264. assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
  3265. assert_select 'option', Project.find(1).users.count + 1 # users + 'me'
  3266. assert_select 'option[value="2"]', :text => 'John Smith'
  3267. end
  3268. assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
  3269. end
  3270. def test_get_new_with_date_custom_field
  3271. field = IssueCustomField.create!(:name => 'Date', :field_format => 'date',
  3272. :tracker_ids => [1], :is_for_all => true)
  3273. @request.session[:user_id] = 2
  3274. get(
  3275. :new,
  3276. :params => {
  3277. :project_id => 1,
  3278. :tracker_id => 1
  3279. }
  3280. )
  3281. assert_response :success
  3282. assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
  3283. end
  3284. def test_get_new_with_text_custom_field
  3285. field = IssueCustomField.create!(:name => 'Text', :field_format => 'text',
  3286. :tracker_ids => [1], :is_for_all => true)
  3287. @request.session[:user_id] = 2
  3288. get(
  3289. :new,
  3290. :params => {
  3291. :project_id => 1,
  3292. :tracker_id => 1
  3293. }
  3294. )
  3295. assert_response :success
  3296. assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
  3297. end
  3298. def test_get_new_without_default_start_date_is_creation_date
  3299. with_settings :default_issue_start_date_to_creation_date => 0 do
  3300. @request.session[:user_id] = 2
  3301. get(
  3302. :new,
  3303. :params => {
  3304. :project_id => 1,
  3305. :tracker_id => 1
  3306. }
  3307. )
  3308. assert_response :success
  3309. assert_select 'input[name=?]', 'issue[start_date]'
  3310. assert_select 'input[name=?][value]', 'issue[start_date]', 0
  3311. end
  3312. end
  3313. def test_get_new_with_default_start_date_is_creation_date
  3314. with_settings :default_issue_start_date_to_creation_date => 1 do
  3315. @request.session[:user_id] = 2
  3316. get(
  3317. :new,
  3318. :params => {
  3319. :project_id => 1,
  3320. :tracker_id => 1
  3321. }
  3322. )
  3323. assert_response :success
  3324. assert_select 'input[name=?][value=?]', 'issue[start_date]',
  3325. Date.today.to_s
  3326. end
  3327. end
  3328. def test_get_new_form_should_allow_attachment_upload
  3329. @request.session[:user_id] = 2
  3330. get(
  3331. :new,
  3332. :params => {
  3333. :project_id => 1,
  3334. :tracker_id => 1
  3335. }
  3336. )
  3337. assert_response :success
  3338. assert_select 'form[id=issue-form][method=post][enctype="multipart/form-data"]' do
  3339. assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
  3340. end
  3341. end
  3342. def test_get_new_should_prefill_the_form_from_params
  3343. @request.session[:user_id] = 2
  3344. get(
  3345. :new,
  3346. :params => {
  3347. :project_id => 1,
  3348. :issue => {
  3349. :tracker_id => 3,
  3350. :description => 'Prefilled',
  3351. :custom_field_values => {
  3352. '2' => 'Custom field value'
  3353. }
  3354. }
  3355. }
  3356. )
  3357. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3358. assert_select 'option[value="3"][selected=selected]'
  3359. end
  3360. assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
  3361. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
  3362. end
  3363. def test_get_new_should_mark_required_fields
  3364. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  3365. :is_for_all => true, :tracker_ids => [1, 2])
  3366. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  3367. :is_for_all => true, :tracker_ids => [1, 2])
  3368. WorkflowPermission.delete_all
  3369. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
  3370. :field_name => 'due_date', :rule => 'required')
  3371. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
  3372. :field_name => cf2.id.to_s, :rule => 'required')
  3373. @request.session[:user_id] = 2
  3374. get(:new, :params => {:project_id => 1})
  3375. assert_response :success
  3376. assert_select 'label[for=issue_start_date]' do
  3377. assert_select 'span[class=required]', 0
  3378. end
  3379. assert_select 'label[for=issue_due_date]' do
  3380. assert_select 'span[class=required]'
  3381. end
  3382. assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
  3383. assert_select 'span[class=required]', 0
  3384. end
  3385. assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
  3386. assert_select 'span[class=required]'
  3387. end
  3388. end
  3389. def test_get_new_should_not_display_readonly_fields
  3390. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  3391. :is_for_all => true, :tracker_ids => [1, 2])
  3392. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  3393. :is_for_all => true, :tracker_ids => [1, 2])
  3394. WorkflowPermission.delete_all
  3395. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
  3396. :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
  3397. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
  3398. :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
  3399. @request.session[:user_id] = 2
  3400. get(:new, :params => {:project_id => 1})
  3401. assert_response :success
  3402. assert_select 'input[name=?]', 'issue[start_date]'
  3403. assert_select 'input[name=?]', 'issue[due_date]', 0
  3404. assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
  3405. assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
  3406. end
  3407. def test_new_with_tracker_set_as_readonly_should_accept_status
  3408. WorkflowPermission.delete_all
  3409. [1, 2].each do |status_id|
  3410. WorkflowPermission.
  3411. create!(
  3412. :tracker_id => 1,
  3413. :old_status_id => status_id,
  3414. :role_id => 1,
  3415. :field_name => 'tracker_id',
  3416. :rule => 'readonly'
  3417. )
  3418. end
  3419. @request.session[:user_id] = 2
  3420. get(
  3421. :new,
  3422. :params => {
  3423. :project_id => 1,
  3424. :issue => {
  3425. :status_id => 2
  3426. }
  3427. }
  3428. )
  3429. assert_select 'select[name=?]', 'issue[tracker_id]', 0
  3430. assert_select 'select[name=?]', 'issue[status_id]' do
  3431. assert_select 'option[value=?][selected=selected]', '2'
  3432. end
  3433. end
  3434. def test_get_new_without_tracker_id
  3435. @request.session[:user_id] = 2
  3436. get(
  3437. :new,
  3438. :params => {
  3439. :project_id => 1
  3440. }
  3441. )
  3442. assert_response :success
  3443. assert_select 'select[name=?]', 'issue[tracker_id]' do
  3444. assert_select 'option[value=?][selected=selected]', Project.find(1).trackers.first.id.to_s
  3445. end
  3446. end
  3447. def test_get_new_with_no_default_status_should_display_an_error
  3448. @request.session[:user_id] = 2
  3449. IssueStatus.delete_all
  3450. get(
  3451. :new,
  3452. :params => {
  3453. :project_id => 1
  3454. }
  3455. )
  3456. assert_response 500
  3457. assert_select_error /No default issue/
  3458. end
  3459. def test_get_new_with_no_tracker_should_display_an_error
  3460. @request.session[:user_id] = 2
  3461. Tracker.delete_all
  3462. get(
  3463. :new,
  3464. :params => {
  3465. :project_id => 1
  3466. }
  3467. )
  3468. assert_response 500
  3469. assert_select_error /No tracker/
  3470. end
  3471. def test_new_with_invalid_project_id
  3472. @request.session[:user_id] = 1
  3473. get(
  3474. :new,
  3475. :params => {
  3476. :project_id => 'invalid'
  3477. }
  3478. )
  3479. assert_response 404
  3480. end
  3481. def test_new_with_parent_id_should_only_propose_valid_trackers
  3482. @request.session[:user_id] = 2
  3483. t = Tracker.find(3)
  3484. assert !t.disabled_core_fields.include?('parent_issue_id')
  3485. get(
  3486. :new,
  3487. :params => {
  3488. :project_id => 1, :issue => {:parent_issue_id => 1}
  3489. }
  3490. )
  3491. assert_response :success
  3492. assert_select 'option', text: /#{t.name}/, count: 1
  3493. t.core_fields = Tracker::CORE_FIELDS - ['parent_issue_id']
  3494. t.save!
  3495. assert t.disabled_core_fields.include?('parent_issue_id')
  3496. get(
  3497. :new,
  3498. :params => {
  3499. :project_id => 1, :issue => {:parent_issue_id => 1}
  3500. }
  3501. )
  3502. assert_response :success
  3503. assert_select 'option', text: /#{t.name}/, count: 0
  3504. end
  3505. def test_get_new_should_show_trackers_description
  3506. @request.session[:user_id] = 2
  3507. get :new, :params => {
  3508. :project_id => 1,
  3509. :issue => {
  3510. :tracker_id => 1
  3511. }
  3512. }
  3513. assert_response :success
  3514. assert_select 'form#issue-form' do
  3515. assert_select 'a[title=?]', 'View all trackers description', :text => 'View all trackers description'
  3516. assert_select 'select[name=?][title=?]', 'issue[tracker_id]', 'Description for Bug tracker'
  3517. end
  3518. assert_select 'div#trackers_description' do
  3519. assert_select 'h3', :text => 'Trackers description', :count => 1
  3520. # only Bug and Feature have descriptions
  3521. assert_select 'dt', 2
  3522. assert_select 'dt', :text => 'Bug', :count => 1
  3523. assert_select 'dd', :text => 'Description for Bug tracker', :count => 1
  3524. end
  3525. end
  3526. def test_get_new_should_not_show_trackers_description_for_trackers_without_description
  3527. Tracker.update_all(:description => '')
  3528. @request.session[:user_id] = 2
  3529. get :new, :params => {
  3530. :project_id => 1,
  3531. :issue => {
  3532. :tracker_id => 1
  3533. }
  3534. }
  3535. assert_response :success
  3536. assert_select 'form#issue-form' do
  3537. assert_select 'a[title=?]', 'View all trackers description', 0
  3538. assert_select 'select[name=?][title=?]', 'issue[tracker_id]', ''
  3539. end
  3540. assert_select 'div#trackers_description', 0
  3541. end
  3542. def test_get_new_should_show_issue_status_description
  3543. @request.session[:user_id] = 2
  3544. get :new, :params => {
  3545. :project_id => 1,
  3546. :issue => {
  3547. :status_id => 2
  3548. }
  3549. }
  3550. assert_response :success
  3551. assert_select 'form#issue-form' do
  3552. assert_select 'a[title=?]', 'View all issue statuses description', :text => 'View all issue statuses description'
  3553. assert_select 'select[name=?][title=?]', 'issue[status_id]', 'Description for Assigned issue status'
  3554. end
  3555. assert_select 'div#issue_statuses_description' do
  3556. assert_select 'h3', :text => 'Issue statuses description', :count => 1
  3557. assert_select 'dt', 2
  3558. assert_select 'dt', :text => 'New', :count => 1
  3559. assert_select 'dd', :text => 'Description for New issue status', :count => 1
  3560. end
  3561. end
  3562. def test_get_new_should_not_show_issue_status_description
  3563. IssueStatus.update_all(:description => '')
  3564. @request.session[:user_id] = 2
  3565. get :new, :params => {
  3566. :project_id => 1,
  3567. :issue => {
  3568. :status_id => 2
  3569. }
  3570. }
  3571. assert_response :success
  3572. assert_select 'form#issue-form' do
  3573. assert_select 'a[title=?]', 'View all issue statuses description', 0
  3574. assert_select 'select[name=?][title=?]', 'issue[status_id]', ''
  3575. end
  3576. assert_select 'div#issue_statuses_description', 0
  3577. end
  3578. def test_get_new_should_show_create_and_follow_button_when_issue_is_subtask_and_back_url_is_present
  3579. @request.session[:user_id] = 2
  3580. get :new, params: {
  3581. project_id: 1,
  3582. issue: {
  3583. parent_issue_id: 2
  3584. },
  3585. back_url: "/issues/2"
  3586. }
  3587. assert_response :success
  3588. assert_select 'form#issue-form' do
  3589. # Assert submit buttons
  3590. assert_select 'input[type=submit][name=?]', 'commit'
  3591. assert_select 'input[type=submit][name=?]', 'continue'
  3592. assert_select 'input[type=submit][name=?]', 'follow'
  3593. end
  3594. end
  3595. def test_update_form_for_new_issue
  3596. @request.session[:user_id] = 2
  3597. post(
  3598. :new,
  3599. :params => {
  3600. :project_id => 1,
  3601. :issue => {
  3602. :tracker_id => 2,
  3603. :subject => 'This is the test_new issue',
  3604. :description => 'This is the description',
  3605. :priority_id => 5
  3606. }
  3607. },
  3608. :xhr => true
  3609. )
  3610. assert_response :success
  3611. assert_equal 'text/javascript', response.media_type
  3612. assert_include 'This is the test_new issue', response.body
  3613. end
  3614. def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
  3615. @request.session[:user_id] = 2
  3616. WorkflowTransition.delete_all
  3617. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3618. :old_status_id => 0, :new_status_id => 2)
  3619. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3620. :old_status_id => 0, :new_status_id => 5)
  3621. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  3622. :old_status_id => 5, :new_status_id => 4)
  3623. post(
  3624. :new,
  3625. :params => {
  3626. :project_id => 1,
  3627. :issue => {
  3628. :tracker_id => 1,
  3629. :status_id => 5,
  3630. :subject => 'This is an issue'
  3631. }
  3632. }
  3633. )
  3634. assert_select 'select[name=?]', 'issue[status_id]' do
  3635. assert_select 'option[value=?][selected=selected]', '5'
  3636. assert_select 'option[value=?]', '2'
  3637. assert_select 'option', :count => 2
  3638. end
  3639. end
  3640. def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
  3641. @request.session[:user_id] = 2
  3642. tracker = Tracker.find(2)
  3643. tracker.update! :default_status_id => 2
  3644. tracker.generate_transitions! 2 => 1, :clear => true
  3645. post(
  3646. :new,
  3647. :params => {
  3648. :project_id => 1,
  3649. :issue => {
  3650. :tracker_id => 2,
  3651. :status_id => 1
  3652. },
  3653. :was_default_status => 1
  3654. }
  3655. )
  3656. assert_response :success
  3657. assert_select 'select[name=?]', 'issue[status_id]' do
  3658. assert_select 'option[value=?][selected=selected]', '2'
  3659. end
  3660. end
  3661. def test_update_form_for_new_issue_should_ignore_version_when_changing_project
  3662. version = Version.generate!(:project_id => 1)
  3663. Project.find(1).update_attribute :default_version_id, version.id
  3664. @request.session[:user_id] = 2
  3665. post(
  3666. :new,
  3667. :params => {
  3668. :issue => {
  3669. :project_id => 1,
  3670. :fixed_version_id => ''
  3671. },
  3672. :form_update_triggered_by => 'issue_project_id'
  3673. }
  3674. )
  3675. assert_response :success
  3676. assert_select 'select[name=?]', 'issue[project_id]' do
  3677. assert_select 'option[value=?][selected=selected]', '1'
  3678. end
  3679. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  3680. assert_select 'option[value=?][selected=selected]', version.id.to_s
  3681. end
  3682. end
  3683. def test_post_create
  3684. @request.session[:user_id] = 2
  3685. assert_difference 'Issue.count' do
  3686. assert_no_difference 'Journal.count' do
  3687. post(
  3688. :create,
  3689. :params => {
  3690. :project_id => 1,
  3691. :issue => {
  3692. :tracker_id => 3,
  3693. :status_id => 2,
  3694. :subject => 'This is the test_new issue',
  3695. :description => 'This is the description',
  3696. :priority_id => 5,
  3697. :start_date => '2010-11-07',
  3698. :estimated_hours => '',
  3699. :custom_field_values => {
  3700. '2' => 'Value for field 2'
  3701. }
  3702. }
  3703. }
  3704. )
  3705. end
  3706. end
  3707. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3708. issue = Issue.find_by_subject('This is the test_new issue')
  3709. assert_not_nil issue
  3710. assert_equal 2, issue.author_id
  3711. assert_equal 3, issue.tracker_id
  3712. assert_equal 2, issue.status_id
  3713. assert_equal Date.parse('2010-11-07'), issue.start_date
  3714. assert_nil issue.estimated_hours
  3715. v = issue.custom_values.where(:custom_field_id => 2).first
  3716. assert_not_nil v
  3717. assert_equal 'Value for field 2', v.value
  3718. end
  3719. def test_post_new_with_group_assignment
  3720. group = Group.find(11)
  3721. project = Project.find(1)
  3722. project.members << Member.new(:principal => group, :roles => [Role.givable.first])
  3723. with_settings :issue_group_assignment => '1' do
  3724. @request.session[:user_id] = 2
  3725. assert_difference 'Issue.count' do
  3726. post(
  3727. :create,
  3728. :params => {
  3729. :project_id => project.id,
  3730. :issue => {
  3731. :tracker_id => 3,
  3732. :status_id => 1,
  3733. :subject => 'This is the test_new_with_group_assignment issue',
  3734. :assigned_to_id => group.id
  3735. }
  3736. }
  3737. )
  3738. end
  3739. end
  3740. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3741. issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
  3742. assert_not_nil issue
  3743. assert_equal group, issue.assigned_to
  3744. end
  3745. def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
  3746. with_settings :default_issue_start_date_to_creation_date => 0 do
  3747. @request.session[:user_id] = 2
  3748. assert_difference 'Issue.count' do
  3749. post(
  3750. :create,
  3751. :params => {
  3752. :project_id => 1,
  3753. :issue => {
  3754. :tracker_id => 3,
  3755. :status_id => 2,
  3756. :subject => 'This is the test_new issue',
  3757. :description => 'This is the description',
  3758. :priority_id => 5,
  3759. :estimated_hours => '',
  3760. :custom_field_values => {
  3761. '2' => 'Value for field 2'
  3762. }
  3763. }
  3764. }
  3765. )
  3766. end
  3767. assert_redirected_to :controller => 'issues', :action => 'show',
  3768. :id => Issue.last.id
  3769. issue = Issue.find_by_subject('This is the test_new issue')
  3770. assert_not_nil issue
  3771. assert_nil issue.start_date
  3772. end
  3773. end
  3774. def test_post_create_without_start_date_and_default_start_date_is_creation_date
  3775. with_settings :default_issue_start_date_to_creation_date => 1 do
  3776. @request.session[:user_id] = 2
  3777. assert_difference 'Issue.count' do
  3778. post(
  3779. :create,
  3780. :params => {
  3781. :project_id => 1,
  3782. :issue => {
  3783. :tracker_id => 3,
  3784. :status_id => 2,
  3785. :subject => 'This is the test_new issue',
  3786. :description => 'This is the description',
  3787. :priority_id => 5,
  3788. :estimated_hours => '',
  3789. :custom_field_values => {
  3790. '2' => 'Value for field 2'
  3791. }
  3792. }
  3793. }
  3794. )
  3795. end
  3796. assert_redirected_to :controller => 'issues', :action => 'show',
  3797. :id => Issue.last.id
  3798. issue = Issue.find_by_subject('This is the test_new issue')
  3799. assert_not_nil issue
  3800. assert_equal Date.today, issue.start_date
  3801. end
  3802. end
  3803. def test_post_create_and_continue
  3804. @request.session[:user_id] = 2
  3805. assert_difference 'Issue.count' do
  3806. post(
  3807. :create,
  3808. :params => {
  3809. :project_id => 1,
  3810. :issue => {
  3811. :tracker_id => 3,
  3812. :subject => 'This is first issue',
  3813. :priority_id => 5
  3814. },
  3815. :continue => ''
  3816. }
  3817. )
  3818. end
  3819. issue = Issue.order('id DESC').first
  3820. assert_redirected_to :controller => 'issues',
  3821. :action => 'new', :project_id => 'ecookbook',
  3822. :issue => {:tracker_id => 3}
  3823. assert_not_nil flash[:notice], "flash was not set"
  3824. assert_select_in flash[:notice],
  3825. 'a[href=?][title=?]', "/issues/#{issue.id}",
  3826. "This is first issue", :text => "##{issue.id}"
  3827. end
  3828. def test_post_create_without_custom_fields_param
  3829. @request.session[:user_id] = 2
  3830. assert_difference 'Issue.count' do
  3831. post(
  3832. :create,
  3833. :params => {
  3834. :project_id => 1,
  3835. :issue => {
  3836. :tracker_id => 1,
  3837. :subject => 'This is the test_new issue',
  3838. :description => 'This is the description',
  3839. :priority_id => 5
  3840. }
  3841. }
  3842. )
  3843. end
  3844. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  3845. end
  3846. def test_post_create_with_multi_custom_field
  3847. field = IssueCustomField.find_by_name('Database')
  3848. field.update_attribute(:multiple, true)
  3849. @request.session[:user_id] = 2
  3850. assert_difference 'Issue.count' do
  3851. post(
  3852. :create,
  3853. :params => {
  3854. :project_id => 1,
  3855. :issue => {
  3856. :tracker_id => 1,
  3857. :subject => 'This is the test_new issue',
  3858. :description => 'This is the description',
  3859. :priority_id => 5,
  3860. :custom_field_values => {
  3861. '1' => ['', 'MySQL', 'Oracle']
  3862. }
  3863. }
  3864. }
  3865. )
  3866. end
  3867. assert_response 302
  3868. issue = Issue.order('id DESC').first
  3869. assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
  3870. end
  3871. def test_post_create_with_empty_multi_custom_field
  3872. field = IssueCustomField.find_by_name('Database')
  3873. field.update_attribute(:multiple, true)
  3874. @request.session[:user_id] = 2
  3875. assert_difference 'Issue.count' do
  3876. post(
  3877. :create,
  3878. :params => {
  3879. :project_id => 1,
  3880. :issue => {
  3881. :tracker_id => 1,
  3882. :subject => 'This is the test_new issue',
  3883. :description => 'This is the description',
  3884. :priority_id => 5,
  3885. :custom_field_values => {
  3886. '1' => ['']
  3887. }
  3888. }
  3889. }
  3890. )
  3891. end
  3892. assert_response 302
  3893. issue = Issue.order('id DESC').first
  3894. assert_equal [''], issue.custom_field_value(1).sort
  3895. end
  3896. def test_post_create_with_multi_user_custom_field
  3897. field =
  3898. IssueCustomField.create!(:name => 'Multi user', :field_format => 'user',
  3899. :multiple => true,
  3900. :tracker_ids => [1], :is_for_all => true)
  3901. @request.session[:user_id] = 2
  3902. assert_difference 'Issue.count' do
  3903. post(
  3904. :create,
  3905. :params => {
  3906. :project_id => 1,
  3907. :issue => {
  3908. :tracker_id => 1,
  3909. :subject => 'This is the test_new issue',
  3910. :description => 'This is the description',
  3911. :priority_id => 5,
  3912. :custom_field_values => {
  3913. field.id.to_s => ['', '2', '3']
  3914. }
  3915. }
  3916. }
  3917. )
  3918. end
  3919. assert_response 302
  3920. issue = Issue.order('id DESC').first
  3921. assert_equal ['2', '3'], issue.custom_field_value(field).sort
  3922. end
  3923. def test_post_create_with_required_custom_field_and_without_custom_fields_param
  3924. field = IssueCustomField.find_by_name('Database')
  3925. field.update_attribute(:is_required, true)
  3926. @request.session[:user_id] = 2
  3927. assert_no_difference 'Issue.count' do
  3928. post(
  3929. :create,
  3930. :params => {
  3931. :project_id => 1,
  3932. :issue => {
  3933. :tracker_id => 1,
  3934. :subject => 'This is the test_new issue',
  3935. :description => 'This is the description',
  3936. :priority_id => 5
  3937. }
  3938. }
  3939. )
  3940. end
  3941. assert_response :success
  3942. assert_select 'label[for=?][class=?]', "issue_custom_field_values_#{field.id}", 'error'
  3943. assert_select_error /Database cannot be blank/
  3944. end
  3945. def test_create_should_validate_required_fields
  3946. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  3947. :is_for_all => true, :tracker_ids => [1, 2])
  3948. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  3949. :is_for_all => true, :tracker_ids => [1, 2])
  3950. WorkflowPermission.delete_all
  3951. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  3952. :field_name => 'due_date', :rule => 'required')
  3953. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  3954. :field_name => cf2.id.to_s, :rule => 'required')
  3955. @request.session[:user_id] = 2
  3956. assert_no_difference 'Issue.count' do
  3957. post(
  3958. :create,
  3959. :params => {
  3960. :project_id => 1,
  3961. :issue => {
  3962. :tracker_id => 2,
  3963. :status_id => 1,
  3964. :subject => 'Test',
  3965. :start_date => '',
  3966. :due_date => '',
  3967. :custom_field_values => {
  3968. cf1.id.to_s => '', cf2.id.to_s => ''
  3969. }
  3970. }
  3971. }
  3972. )
  3973. assert_response :success
  3974. end
  3975. assert_select 'label[for=?][class=?]', 'issue_due_date', 'error'
  3976. assert_select 'label[for=?][class=?]', "issue_custom_field_values_#{cf2.id}", 'error'
  3977. assert_select_error /Due date cannot be blank/i
  3978. assert_select_error /Bar cannot be blank/i
  3979. end
  3980. def test_create_should_validate_required_list_fields
  3981. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'list',
  3982. :is_for_all => true, :tracker_ids => [1, 2],
  3983. :multiple => false, :possible_values => ['a', 'b'])
  3984. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'list',
  3985. :is_for_all => true, :tracker_ids => [1, 2],
  3986. :multiple => true, :possible_values => ['a', 'b'])
  3987. WorkflowPermission.delete_all
  3988. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  3989. :field_name => cf1.id.to_s, :rule => 'required')
  3990. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  3991. :field_name => cf2.id.to_s, :rule => 'required')
  3992. @request.session[:user_id] = 2
  3993. assert_no_difference 'Issue.count' do
  3994. post(
  3995. :create,
  3996. :params => {
  3997. :project_id => 1,
  3998. :issue => {
  3999. :tracker_id => 2,
  4000. :status_id => 1,
  4001. :subject => 'Test',
  4002. :start_date => '',
  4003. :due_date => '',
  4004. :custom_field_values => {
  4005. cf1.id.to_s => '', cf2.id.to_s => ['']
  4006. }
  4007. }
  4008. }
  4009. )
  4010. assert_response :success
  4011. end
  4012. assert_select_error /Foo cannot be blank/i
  4013. assert_select_error /Bar cannot be blank/i
  4014. end
  4015. def test_create_should_ignore_readonly_fields
  4016. cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
  4017. :is_for_all => true, :tracker_ids => [1, 2])
  4018. cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string',
  4019. :is_for_all => true, :tracker_ids => [1, 2])
  4020. WorkflowPermission.delete_all
  4021. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4022. :field_name => 'due_date', :rule => 'readonly')
  4023. WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1,
  4024. :field_name => cf2.id.to_s, :rule => 'readonly')
  4025. @request.session[:user_id] = 2
  4026. assert_difference 'Issue.count' do
  4027. post(
  4028. :create,
  4029. :params => {
  4030. :project_id => 1,
  4031. :issue => {
  4032. :tracker_id => 2,
  4033. :status_id => 1,
  4034. :subject => 'Test',
  4035. :start_date => '2012-07-14',
  4036. :due_date => '2012-07-16',
  4037. :custom_field_values => {
  4038. cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
  4039. }
  4040. }
  4041. }
  4042. )
  4043. assert_response 302
  4044. end
  4045. issue = Issue.order('id DESC').first
  4046. assert_equal Date.parse('2012-07-14'), issue.start_date
  4047. assert_nil issue.due_date
  4048. assert_equal 'value1', issue.custom_field_value(cf1)
  4049. assert_nil issue.custom_field_value(cf2)
  4050. end
  4051. def test_create_should_ignore_unallowed_trackers
  4052. role = Role.find(1)
  4053. role.set_permission_trackers :add_issues, [3]
  4054. role.save!
  4055. @request.session[:user_id] = 2
  4056. issue = new_record(Issue) do
  4057. post(
  4058. :create,
  4059. :params => {
  4060. :project_id => 1,
  4061. :issue => {
  4062. :tracker_id => 1,
  4063. :status_id => 1,
  4064. :subject => 'Test'
  4065. }
  4066. }
  4067. )
  4068. assert_response 302
  4069. end
  4070. assert_equal 3, issue.tracker_id
  4071. end
  4072. def test_post_create_with_watchers
  4073. @request.session[:user_id] = 2
  4074. ActionMailer::Base.deliveries.clear
  4075. with_settings :notified_events => %w(issue_added) do
  4076. assert_difference 'Watcher.count', 3 do
  4077. post(
  4078. :create,
  4079. :params => {
  4080. :project_id => 1,
  4081. :issue => {
  4082. :tracker_id => 1,
  4083. :subject => 'This is a new issue with watchers',
  4084. :description => 'This is the description',
  4085. :priority_id => 5,
  4086. :watcher_user_ids => ['2', '3', '10']
  4087. }
  4088. }
  4089. )
  4090. end
  4091. end
  4092. issue = Issue.find_by_subject('This is a new issue with watchers')
  4093. assert_not_nil issue
  4094. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
  4095. # Watchers added
  4096. assert_equal [2, 3, 10], issue.watcher_user_ids.sort
  4097. assert issue.watched_by?(User.find(3))
  4098. assert issue.watched_by?(Group.find(10))
  4099. # Watchers notified
  4100. assert_equal 3, ActionMailer::Base.deliveries.size
  4101. mail = ActionMailer::Base.deliveries[1]
  4102. assert [mail.to].flatten.include?(User.find(3).mail)
  4103. mail = ActionMailer::Base.deliveries[2]
  4104. assert [mail.to].flatten.include?(User.find(8).mail)
  4105. end
  4106. def test_post_create_subissue
  4107. @request.session[:user_id] = 2
  4108. assert_difference 'Issue.count' do
  4109. post(
  4110. :create,
  4111. :params => {
  4112. :project_id => 1,
  4113. :issue => {
  4114. :tracker_id => 1,
  4115. :subject => 'This is a child issue',
  4116. :parent_issue_id => '2'
  4117. }
  4118. }
  4119. )
  4120. assert_response 302
  4121. end
  4122. issue = Issue.order('id DESC').first
  4123. assert_equal Issue.find(2), issue.parent
  4124. end
  4125. def test_post_create_subissue_with_sharp_parent_id
  4126. @request.session[:user_id] = 2
  4127. assert_difference 'Issue.count' do
  4128. post(
  4129. :create,
  4130. :params => {
  4131. :project_id => 1,
  4132. :issue => {
  4133. :tracker_id => 1,
  4134. :subject => 'This is a child issue',
  4135. :parent_issue_id => '#2'
  4136. }
  4137. }
  4138. )
  4139. assert_response 302
  4140. end
  4141. issue = Issue.order('id DESC').first
  4142. assert_equal Issue.find(2), issue.parent
  4143. end
  4144. def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
  4145. @request.session[:user_id] = 2
  4146. assert_no_difference 'Issue.count' do
  4147. post(
  4148. :create,
  4149. :params => {
  4150. :project_id => 1,
  4151. :issue => {
  4152. :tracker_id => 1,
  4153. :subject => 'This is a child issue',
  4154. :parent_issue_id => '4'
  4155. }
  4156. }
  4157. )
  4158. assert_response :success
  4159. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
  4160. assert_select_error /Parent task is invalid/i
  4161. end
  4162. end
  4163. def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
  4164. @request.session[:user_id] = 2
  4165. assert_no_difference 'Issue.count' do
  4166. post(
  4167. :create,
  4168. :params => {
  4169. :project_id => 1,
  4170. :issue => {
  4171. :tracker_id => 1,
  4172. :subject => 'This is a child issue',
  4173. :parent_issue_id => '01ABC'
  4174. }
  4175. }
  4176. )
  4177. assert_response :success
  4178. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
  4179. assert_select_error /Parent task is invalid/i
  4180. end
  4181. end
  4182. def test_post_create_private
  4183. @request.session[:user_id] = 2
  4184. assert_difference 'Issue.count' do
  4185. post(
  4186. :create,
  4187. :params => {
  4188. :project_id => 1,
  4189. :issue => {
  4190. :tracker_id => 1,
  4191. :subject => 'This is a private issue',
  4192. :is_private => '1'
  4193. }
  4194. }
  4195. )
  4196. end
  4197. issue = Issue.order('id DESC').first
  4198. assert issue.is_private?
  4199. end
  4200. def test_post_create_private_with_set_own_issues_private_permission
  4201. role = Role.find(1)
  4202. role.remove_permission! :set_issues_private
  4203. role.add_permission! :set_own_issues_private
  4204. @request.session[:user_id] = 2
  4205. assert_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 private issue',
  4213. :is_private => '1'
  4214. }
  4215. }
  4216. )
  4217. end
  4218. issue = Issue.order('id DESC').first
  4219. assert issue.is_private?
  4220. end
  4221. def test_create_without_project_id
  4222. @request.session[:user_id] = 2
  4223. assert_difference 'Issue.count' do
  4224. post(
  4225. :create,
  4226. :params => {
  4227. :issue => {
  4228. :project_id => 3,
  4229. :tracker_id => 2,
  4230. :subject => 'Foo'
  4231. }
  4232. }
  4233. )
  4234. assert_response 302
  4235. end
  4236. issue = Issue.order('id DESC').first
  4237. assert_equal 3, issue.project_id
  4238. assert_equal 2, issue.tracker_id
  4239. end
  4240. def test_create_without_project_id_and_continue_should_redirect_without_project_id
  4241. @request.session[:user_id] = 2
  4242. assert_difference 'Issue.count' do
  4243. post(
  4244. :create,
  4245. :params => {
  4246. :issue => {
  4247. :project_id => 3,
  4248. :tracker_id => 2,
  4249. :subject => 'Foo'
  4250. },
  4251. :continue => '1'
  4252. }
  4253. )
  4254. assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
  4255. end
  4256. end
  4257. def test_create_without_project_id_should_be_denied_without_permission
  4258. Role.non_member.remove_permission! :add_issues
  4259. Role.anonymous.remove_permission! :add_issues
  4260. @request.session[:user_id] = 2
  4261. assert_no_difference 'Issue.count' do
  4262. post(
  4263. :create,
  4264. :params => {
  4265. :issue => {
  4266. :project_id => 3,
  4267. :tracker_id => 2,
  4268. :subject => 'Foo'
  4269. }
  4270. }
  4271. )
  4272. assert_response 422
  4273. end
  4274. end
  4275. def test_create_without_project_id_with_failure_should_not_set_project
  4276. @request.session[:user_id] = 2
  4277. post(
  4278. :create,
  4279. :params => {
  4280. :issue => {
  4281. :project_id => 3,
  4282. :tracker_id => 2,
  4283. :subject => ''
  4284. }
  4285. }
  4286. )
  4287. assert_response :success
  4288. # no project menu
  4289. assert_select '#main-menu a.overview', 0
  4290. end
  4291. def test_post_create_should_send_a_notification
  4292. ActionMailer::Base.deliveries.clear
  4293. @request.session[:user_id] = 2
  4294. with_settings :notified_events => %w(issue_added) do
  4295. assert_difference 'Issue.count' do
  4296. post(
  4297. :create,
  4298. :params => {
  4299. :project_id => 1,
  4300. :issue => {
  4301. :tracker_id => 3,
  4302. :subject => 'This is the test_new issue',
  4303. :description => 'This is the description',
  4304. :priority_id => 5,
  4305. :estimated_hours => '',
  4306. :custom_field_values => {
  4307. '2' => 'Value for field 2'
  4308. }
  4309. }
  4310. }
  4311. )
  4312. end
  4313. assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
  4314. assert_equal 2, ActionMailer::Base.deliveries.size
  4315. end
  4316. end
  4317. def test_post_create_should_preserve_fields_values_on_validation_failure
  4318. @request.session[:user_id] = 2
  4319. post(
  4320. :create,
  4321. :params => {
  4322. :project_id => 1,
  4323. :issue => {
  4324. :tracker_id => 1,
  4325. :subject => '', # empty subject
  4326. :description => 'This is a description',
  4327. :priority_id => 6,
  4328. :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}
  4329. }
  4330. }
  4331. )
  4332. assert_response :success
  4333. assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
  4334. assert_select 'select[name=?]', 'issue[priority_id]' do
  4335. assert_select 'option[value="6"][selected=selected]', :text => 'High'
  4336. end
  4337. # Custom fields
  4338. assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
  4339. assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
  4340. end
  4341. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
  4342. end
  4343. def test_post_create_with_failure_should_preserve_watchers
  4344. assert !User.find(8).member_of?(Project.find(1))
  4345. @request.session[:user_id] = 2
  4346. post(
  4347. :create,
  4348. :params => {
  4349. :project_id => 1,
  4350. :issue => {
  4351. :tracker_id => 1,
  4352. :watcher_user_ids => ['3', '8']
  4353. }
  4354. }
  4355. )
  4356. assert_response :success
  4357. assert_select 'input[name=?][value="2"]:not(checked)', 'issue[watcher_user_ids][]'
  4358. assert_select 'input[name=?][value="3"][checked=checked]', 'issue[watcher_user_ids][]'
  4359. assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]'
  4360. end
  4361. def test_post_create_with_failure_should_not_dereference_group_watchers
  4362. @request.session[:user_id] = 1
  4363. post(
  4364. :create,
  4365. :params => {
  4366. :project_id => 5,
  4367. :issue => {
  4368. :tracker_id => 1,
  4369. :watcher_user_ids => ['11']
  4370. }
  4371. }
  4372. )
  4373. assert_response :success
  4374. assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]', 0
  4375. assert_select 'input[name=?][value="11"][checked=checked]', 'issue[watcher_user_ids][]', 1
  4376. end
  4377. def test_post_create_should_ignore_non_safe_attributes
  4378. @request.session[:user_id] = 2
  4379. assert_nothing_raised do
  4380. post(
  4381. :create,
  4382. :params => {
  4383. :project_id => 1,
  4384. :issue => {
  4385. :tracker => "A param can not be a Tracker"
  4386. }
  4387. }
  4388. )
  4389. end
  4390. end
  4391. def test_post_create_with_attachment
  4392. set_tmp_attachments_directory
  4393. @request.session[:user_id] = 2
  4394. assert_difference 'Issue.count' do
  4395. assert_difference 'Attachment.count' do
  4396. assert_no_difference 'Journal.count' do
  4397. post(
  4398. :create,
  4399. :params => {
  4400. :project_id => 1,
  4401. :issue => {
  4402. :tracker_id => '1',
  4403. :subject => 'With attachment'
  4404. },
  4405. :attachments => {
  4406. '1' => {
  4407. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4408. 'description' => 'test file'
  4409. }
  4410. }
  4411. }
  4412. )
  4413. end
  4414. end
  4415. end
  4416. issue = Issue.order('id DESC').first
  4417. attachment = Attachment.order('id DESC').first
  4418. assert_equal issue, attachment.container
  4419. assert_equal 2, attachment.author_id
  4420. assert_equal 'testfile.txt', attachment.filename
  4421. assert_equal 'text/plain', attachment.content_type
  4422. assert_equal 'test file', attachment.description
  4423. assert_equal 59, attachment.filesize
  4424. assert File.exist?(attachment.diskfile)
  4425. assert_equal 59, File.size(attachment.diskfile)
  4426. end
  4427. def test_post_create_with_attachment_should_notify_with_attachments
  4428. ActionMailer::Base.deliveries.clear
  4429. set_tmp_attachments_directory
  4430. @request.session[:user_id] = 2
  4431. with_settings :notified_events => %w(issue_added) do
  4432. assert_difference 'Issue.count' do
  4433. post(
  4434. :create,
  4435. :params => {
  4436. :project_id => 1,
  4437. :issue => {
  4438. :tracker_id => '1',
  4439. :subject => 'With attachment'
  4440. },
  4441. :attachments => {
  4442. '1' => {
  4443. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4444. 'description' => 'test file'
  4445. }
  4446. }
  4447. }
  4448. )
  4449. end
  4450. end
  4451. assert_not_nil ActionMailer::Base.deliveries.last
  4452. assert_select_email do
  4453. assert_select 'a[href^=?]', 'http://localhost:3000/attachments/download', 'testfile.txt'
  4454. end
  4455. end
  4456. def test_post_create_with_failure_should_save_attachments
  4457. set_tmp_attachments_directory
  4458. @request.session[:user_id] = 2
  4459. assert_no_difference 'Issue.count' do
  4460. assert_difference 'Attachment.count' do
  4461. post(
  4462. :create,
  4463. :params => {
  4464. :project_id => 1,
  4465. :issue => {
  4466. :tracker_id => '1',
  4467. :subject => ''
  4468. },
  4469. :attachments => {
  4470. '1' => {
  4471. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4472. 'description' => 'test file'
  4473. }
  4474. }
  4475. }
  4476. )
  4477. assert_response :success
  4478. end
  4479. end
  4480. attachment = Attachment.order('id DESC').first
  4481. assert_equal 'testfile.txt', attachment.filename
  4482. assert File.exist?(attachment.diskfile)
  4483. assert_nil attachment.container
  4484. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  4485. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  4486. end
  4487. def test_post_create_with_failure_should_keep_saved_attachments
  4488. set_tmp_attachments_directory
  4489. attachment =
  4490. Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"),
  4491. :author_id => 2)
  4492. @request.session[:user_id] = 2
  4493. assert_no_difference 'Issue.count' do
  4494. assert_no_difference 'Attachment.count' do
  4495. post(
  4496. :create,
  4497. :params => {
  4498. :project_id => 1,
  4499. :issue => {
  4500. :tracker_id => '1',
  4501. :subject => ''
  4502. },
  4503. :attachments => {
  4504. 'p0' => {
  4505. 'token' => attachment.token
  4506. }
  4507. }
  4508. }
  4509. )
  4510. assert_response :success
  4511. end
  4512. end
  4513. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  4514. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  4515. end
  4516. def test_post_create_should_attach_saved_attachments
  4517. set_tmp_attachments_directory
  4518. attachment =
  4519. Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"),
  4520. :author_id => 2)
  4521. @request.session[:user_id] = 2
  4522. assert_difference 'Issue.count' do
  4523. assert_no_difference 'Attachment.count' do
  4524. post(
  4525. :create,
  4526. :params => {
  4527. :project_id => 1,
  4528. :issue => {
  4529. :tracker_id => '1',
  4530. :subject => 'Saved attachments'
  4531. },
  4532. :attachments => {
  4533. 'p0' => {
  4534. 'token' => attachment.token
  4535. }
  4536. }
  4537. }
  4538. )
  4539. assert_response 302
  4540. end
  4541. end
  4542. issue = Issue.order('id DESC').first
  4543. assert_equal 1, issue.attachments.count
  4544. attachment.reload
  4545. assert_equal issue, attachment.container
  4546. end
  4547. def setup_without_workflow_privilege
  4548. WorkflowTransition.where(["role_id = ?", Role.anonymous.id]).delete_all
  4549. Role.anonymous.add_permission! :add_issues, :add_issue_notes
  4550. end
  4551. private :setup_without_workflow_privilege
  4552. test "without workflow privilege #new should propose default status only" do
  4553. setup_without_workflow_privilege
  4554. get(:new, :params => {:project_id => 1})
  4555. assert_response :success
  4556. assert_select 'select[name=?]', 'issue[status_id]' do
  4557. assert_select 'option', 1
  4558. assert_select 'option[value=?][selected=selected]', '1'
  4559. end
  4560. end
  4561. test "without workflow privilege #create should accept default status" do
  4562. setup_without_workflow_privilege
  4563. assert_difference 'Issue.count' do
  4564. post(
  4565. :create,
  4566. :params => {
  4567. :project_id => 1,
  4568. :issue => {
  4569. :tracker_id => 1,
  4570. :subject => 'This is an issue',
  4571. :status_id => 1
  4572. }
  4573. }
  4574. )
  4575. end
  4576. issue = Issue.order('id').last
  4577. assert_not_nil issue.default_status
  4578. assert_equal issue.default_status, issue.status
  4579. end
  4580. test "without workflow privilege #create should ignore unauthorized status" do
  4581. setup_without_workflow_privilege
  4582. assert_difference 'Issue.count' do
  4583. post(
  4584. :create,
  4585. :params => {
  4586. :project_id => 1,
  4587. :issue => {
  4588. :tracker_id => 1,
  4589. :subject => 'This is an issue',
  4590. :status_id => 3
  4591. }
  4592. }
  4593. )
  4594. end
  4595. issue = Issue.order('id').last
  4596. assert_not_nil issue.default_status
  4597. assert_equal issue.default_status, issue.status
  4598. end
  4599. test "without workflow privilege #update should ignore status change" do
  4600. setup_without_workflow_privilege
  4601. assert_difference 'Journal.count' do
  4602. put(
  4603. :update,
  4604. :params => {
  4605. :id => 1,
  4606. :issue => {
  4607. :status_id => 3,
  4608. :notes => 'just trying'
  4609. }
  4610. }
  4611. )
  4612. end
  4613. assert_equal 1, Issue.find(1).status_id
  4614. end
  4615. test "without workflow privilege #update ignore attributes changes" do
  4616. setup_without_workflow_privilege
  4617. assert_difference 'Journal.count' do
  4618. put(
  4619. :update,
  4620. :params => {
  4621. :id => 1,
  4622. :issue => {
  4623. :subject => 'changed',
  4624. :assigned_to_id => 2,
  4625. :notes => 'just trying'
  4626. }
  4627. }
  4628. )
  4629. end
  4630. issue = Issue.find(1)
  4631. assert_equal "Cannot print recipes", issue.subject
  4632. assert_nil issue.assigned_to
  4633. end
  4634. def setup_with_workflow_privilege
  4635. WorkflowTransition.where(["role_id = ?", Role.anonymous.id]).delete_all
  4636. WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
  4637. :old_status_id => 1, :new_status_id => 3)
  4638. WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
  4639. :old_status_id => 1, :new_status_id => 4)
  4640. Role.anonymous.add_permission! :add_issues, :add_issue_notes
  4641. end
  4642. private :setup_with_workflow_privilege
  4643. def setup_with_workflow_privilege_and_edit_issues_permission
  4644. setup_with_workflow_privilege
  4645. Role.anonymous.add_permission! :add_issues, :edit_issues
  4646. end
  4647. private :setup_with_workflow_privilege_and_edit_issues_permission
  4648. test "with workflow privilege and :edit_issues permission should accept authorized status" do
  4649. setup_with_workflow_privilege_and_edit_issues_permission
  4650. assert_difference 'Journal.count' do
  4651. put(
  4652. :update,
  4653. :params => {
  4654. :id => 1,
  4655. :issue => {
  4656. :status_id => 3,
  4657. :notes => 'just trying'
  4658. }
  4659. }
  4660. )
  4661. end
  4662. assert_equal 3, Issue.find(1).status_id
  4663. end
  4664. test "with workflow privilege and :edit_issues permission should ignore unauthorized status" do
  4665. setup_with_workflow_privilege_and_edit_issues_permission
  4666. assert_difference 'Journal.count' do
  4667. put(
  4668. :update,
  4669. :params => {
  4670. :id => 1,
  4671. :issue => {
  4672. :status_id => 2,
  4673. :notes => 'just trying'
  4674. }
  4675. }
  4676. )
  4677. end
  4678. assert_equal 1, Issue.find(1).status_id
  4679. end
  4680. test "with workflow privilege and :edit_issues permission should accept authorized attributes changes" do
  4681. setup_with_workflow_privilege_and_edit_issues_permission
  4682. assert_difference 'Journal.count' do
  4683. put(
  4684. :update,
  4685. :params => {
  4686. :id => 1,
  4687. :issue => {
  4688. :subject => 'changed',
  4689. :assigned_to_id => 2,
  4690. :notes => 'just trying'
  4691. }
  4692. }
  4693. )
  4694. end
  4695. issue = Issue.find(1)
  4696. assert_equal "changed", issue.subject
  4697. assert_equal 2, issue.assigned_to_id
  4698. end
  4699. def test_new_as_copy
  4700. orig = Issue.find(1)
  4701. @request.session[:user_id] = 2
  4702. get(
  4703. :new,
  4704. :params => {
  4705. :project_id => 1,
  4706. :copy_from => orig.id
  4707. }
  4708. )
  4709. assert_response :success
  4710. assert_select 'form[id=issue-form][action="/projects/ecookbook/issues"]' do
  4711. assert_select 'select[name=?]', 'issue[project_id]' do
  4712. assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook'
  4713. assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore'
  4714. end
  4715. assert_select 'input[name=?][value=?]', 'issue[subject]', orig.subject
  4716. assert_select 'input[name=copy_from][value="1"]'
  4717. end
  4718. end
  4719. def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
  4720. user = setup_user_with_copy_but_not_add_permission
  4721. @request.session[:user_id] = user.id
  4722. get(
  4723. :new,
  4724. :params => {
  4725. :project_id => 1,
  4726. :copy_from => 1
  4727. }
  4728. )
  4729. assert_response :success
  4730. assert_select 'select[name=?]', 'issue[project_id]' do
  4731. assert_select 'option[value="1"]', 0
  4732. assert_select 'option[value="2"]', :text => 'OnlineStore'
  4733. end
  4734. end
  4735. def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
  4736. @request.session[:user_id] = 2
  4737. issue = Issue.find(3)
  4738. assert issue.attachments.count > 0
  4739. get(
  4740. :new,
  4741. :params => {
  4742. :project_id => 1,
  4743. :copy_from => 3
  4744. }
  4745. )
  4746. assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value="1"]'
  4747. end
  4748. def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
  4749. @request.session[:user_id] = 2
  4750. issue = Issue.find(3)
  4751. issue.attachments.delete_all
  4752. get(
  4753. :new,
  4754. :params => {
  4755. :project_id => 1,
  4756. :copy_from => 3
  4757. }
  4758. )
  4759. assert_select 'input[name=copy_attachments]', 0
  4760. end
  4761. def test_new_as_copy_should_preserve_parent_id
  4762. @request.session[:user_id] = 2
  4763. issue = Issue.generate!(:parent_issue_id => 2)
  4764. get(
  4765. :new,
  4766. :params => {
  4767. :project_id => 1,
  4768. :copy_from => issue.id
  4769. }
  4770. )
  4771. assert_select 'input[name=?][value="2"]', 'issue[parent_issue_id]'
  4772. end
  4773. def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
  4774. @request.session[:user_id] = 2
  4775. issue = Issue.generate_with_descendants!
  4776. get(
  4777. :new,
  4778. :params => {
  4779. :project_id => 1,
  4780. :copy_from => issue.id
  4781. }
  4782. )
  4783. assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value="1"]'
  4784. end
  4785. def test_new_as_copy_should_preserve_watchers
  4786. @request.session[:user_id] = 2
  4787. issue = Issue.find(1)
  4788. user = User.generate!
  4789. Watcher.create!(:watchable => issue, :user => user)
  4790. Watcher.create!(:watchable => issue, :user => Group.find(10))
  4791. get(
  4792. :new,
  4793. :params => {
  4794. :project_id => 1,
  4795. :copy_from => 1
  4796. }
  4797. )
  4798. assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 2
  4799. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4800. 'issue[watcher_user_ids][]', user.id.to_s
  4801. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4802. 'issue[watcher_user_ids][]', '10'
  4803. assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1
  4804. end
  4805. def test_new_as_copy_should_not_propose_locked_watchers
  4806. @request.session[:user_id] = 2
  4807. issue = Issue.find(1)
  4808. user = User.generate!
  4809. user2 = User.generate!
  4810. Watcher.create!(:watchable => issue, :user => user)
  4811. Watcher.create!(:watchable => issue, :user => user2)
  4812. user2.status = User::STATUS_LOCKED
  4813. user2.save!
  4814. get(
  4815. :new,
  4816. :params => {
  4817. :project_id => 1,
  4818. :copy_from => 1
  4819. }
  4820. )
  4821. assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 1
  4822. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4823. 'issue[watcher_user_ids][]', user.id.to_s
  4824. assert_select 'input[type=checkbox][name=?][checked=checked][value=?]',
  4825. 'issue[watcher_user_ids][]', user2.id.to_s, 0
  4826. assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1
  4827. end
  4828. def test_new_as_copy_with_invalid_issue_should_respond_with_404
  4829. @request.session[:user_id] = 2
  4830. get(
  4831. :new,
  4832. :params => {
  4833. :project_id => 1,
  4834. :copy_from => 99999
  4835. }
  4836. )
  4837. assert_response 404
  4838. end
  4839. def test_create_as_copy_on_different_project
  4840. @request.session[:user_id] = 2
  4841. assert_difference 'Issue.count' do
  4842. post(
  4843. :create,
  4844. :params => {
  4845. :project_id => 1,
  4846. :copy_from => 1,
  4847. :issue => {
  4848. :project_id => '2',
  4849. :tracker_id => '3',
  4850. :status_id => '1',
  4851. :subject => 'Copy'
  4852. }
  4853. }
  4854. )
  4855. end
  4856. issue = Issue.order('id DESC').first
  4857. assert_redirected_to "/issues/#{issue.id}"
  4858. assert_equal 2, issue.project_id
  4859. assert_equal 3, issue.tracker_id
  4860. assert_equal 'Copy', issue.subject
  4861. end
  4862. def test_create_as_copy_should_allow_status_to_be_set_to_default
  4863. copied = Issue.generate! :status_id => 2
  4864. assert_equal 2, copied.reload.status_id
  4865. @request.session[:user_id] = 2
  4866. assert_difference 'Issue.count' do
  4867. post(
  4868. :create,
  4869. :params => {
  4870. :project_id => 1,
  4871. :copy_from => copied.id,
  4872. :issue => {
  4873. :project_id => '1',
  4874. :tracker_id => '1',
  4875. :status_id => '1'
  4876. },
  4877. :was_default_status => '1'
  4878. }
  4879. )
  4880. end
  4881. issue = Issue.order('id DESC').first
  4882. assert_equal 1, issue.status_id
  4883. end
  4884. def test_create_as_copy_should_fail_without_add_issue_permission_on_original_tracker
  4885. role = Role.find(2)
  4886. role.set_permission_trackers :add_issues, [1, 3]
  4887. role.save!
  4888. Role.non_member.remove_permission! :add_issues
  4889. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  4890. @request.session[:user_id] = 3
  4891. assert_no_difference 'Issue.count' do
  4892. post(
  4893. :create,
  4894. :params => {
  4895. :project_id => 1,
  4896. :copy_from => issue.id,
  4897. :issue => {
  4898. :project_id => '1'
  4899. }
  4900. }
  4901. )
  4902. end
  4903. assert_select_error 'Tracker is invalid'
  4904. end
  4905. def test_create_as_copy_should_copy_attachments
  4906. @request.session[:user_id] = 2
  4907. issue = Issue.find(3)
  4908. count = issue.attachments.count
  4909. assert count > 0
  4910. assert_difference 'Issue.count' do
  4911. assert_difference 'Attachment.count', count do
  4912. post(
  4913. :create,
  4914. :params => {
  4915. :project_id => 1,
  4916. :copy_from => 3,
  4917. :issue => {
  4918. :project_id => '1',
  4919. :tracker_id => '3',
  4920. :status_id => '1',
  4921. :subject => 'Copy with attachments'
  4922. },
  4923. :copy_attachments => '1'
  4924. }
  4925. )
  4926. end
  4927. end
  4928. copy = Issue.order('id DESC').first
  4929. assert_equal count, copy.attachments.count
  4930. assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
  4931. end
  4932. def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
  4933. @request.session[:user_id] = 2
  4934. issue = Issue.find(3)
  4935. count = issue.attachments.count
  4936. assert count > 0
  4937. assert_difference 'Issue.count' do
  4938. assert_no_difference 'Attachment.count' do
  4939. post(
  4940. :create,
  4941. :params => {
  4942. :project_id => 1,
  4943. :copy_from => 3,
  4944. :issue => {
  4945. :project_id => '1',
  4946. :tracker_id => '3',
  4947. :status_id => '1',
  4948. :subject => 'Copy with attachments'
  4949. }
  4950. }
  4951. )
  4952. end
  4953. end
  4954. copy = Issue.order('id DESC').first
  4955. assert_equal 0, copy.attachments.count
  4956. end
  4957. def test_create_as_copy_with_attachments_should_also_add_new_files
  4958. set_tmp_attachments_directory
  4959. @request.session[:user_id] = 2
  4960. issue = Issue.find(3)
  4961. count = issue.attachments.count
  4962. assert count > 0
  4963. assert_difference 'Issue.count' do
  4964. assert_difference 'Attachment.count', count + 1 do
  4965. post(
  4966. :create,
  4967. :params => {
  4968. :project_id => 1,
  4969. :copy_from => 3,
  4970. :issue => {
  4971. :project_id => '1',
  4972. :tracker_id => '3',
  4973. :status_id => '1',
  4974. :subject => 'Copy with attachments'
  4975. },
  4976. :copy_attachments => '1',
  4977. :attachments => {
  4978. '1' => {
  4979. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  4980. 'description' => 'test file'
  4981. }
  4982. }
  4983. }
  4984. )
  4985. end
  4986. end
  4987. copy = Issue.order('id DESC').first
  4988. assert_equal count + 1, copy.attachments.count
  4989. end
  4990. def test_create_as_copy_should_add_relation_with_copied_issue
  4991. @request.session[:user_id] = 2
  4992. assert_difference 'Issue.count' do
  4993. assert_difference 'IssueRelation.count' do
  4994. post(
  4995. :create,
  4996. :params => {
  4997. :project_id => 1,
  4998. :copy_from => 1,
  4999. :link_copy => '1',
  5000. :issue => {
  5001. :project_id => '1',
  5002. :tracker_id => '3',
  5003. :status_id => '1',
  5004. :subject => 'Copy'
  5005. }
  5006. }
  5007. )
  5008. end
  5009. end
  5010. copy = Issue.order('id DESC').first
  5011. assert_equal 1, copy.relations.size
  5012. end
  5013. def test_create_as_copy_should_allow_not_to_add_relation_with_copied_issue
  5014. @request.session[:user_id] = 2
  5015. assert_difference 'Issue.count' do
  5016. assert_no_difference 'IssueRelation.count' do
  5017. post(
  5018. :create,
  5019. :params => {
  5020. :project_id => 1,
  5021. :copy_from => 1,
  5022. :issue => {
  5023. :subject => 'Copy'
  5024. }
  5025. }
  5026. )
  5027. end
  5028. end
  5029. end
  5030. def test_create_as_copy_should_always_add_relation_with_copied_issue_by_setting
  5031. with_settings :link_copied_issue => 'yes' do
  5032. @request.session[:user_id] = 2
  5033. assert_difference 'Issue.count' do
  5034. assert_difference 'IssueRelation.count' do
  5035. post(
  5036. :create,
  5037. :params => {
  5038. :project_id => 1,
  5039. :copy_from => 1,
  5040. :issue => {
  5041. :subject => 'Copy'
  5042. }
  5043. }
  5044. )
  5045. end
  5046. end
  5047. end
  5048. end
  5049. def test_create_as_copy_should_never_add_relation_with_copied_issue_by_setting
  5050. with_settings :link_copied_issue => 'no' do
  5051. @request.session[:user_id] = 2
  5052. assert_difference 'Issue.count' do
  5053. assert_no_difference 'IssueRelation.count' do
  5054. post(
  5055. :create,
  5056. :params => {
  5057. :project_id => 1,
  5058. :copy_from => 1,
  5059. :link_copy => '1',
  5060. :issue => {
  5061. :subject => 'Copy'
  5062. }
  5063. }
  5064. )
  5065. end
  5066. end
  5067. end
  5068. end
  5069. def test_create_as_copy_should_copy_subtasks
  5070. @request.session[:user_id] = 2
  5071. issue = Issue.generate_with_descendants!
  5072. count = issue.descendants.count
  5073. assert_difference 'Issue.count', count + 1 do
  5074. post(
  5075. :create,
  5076. :params => {
  5077. :project_id => 1,
  5078. :copy_from => issue.id,
  5079. :issue => {
  5080. :project_id => '1',
  5081. :tracker_id => '3',
  5082. :status_id => '1',
  5083. :subject => 'Copy with subtasks'
  5084. },
  5085. :copy_subtasks => '1'
  5086. }
  5087. )
  5088. end
  5089. copy = Issue.where(:parent_id => nil).order('id DESC').first
  5090. assert_equal count, copy.descendants.count
  5091. assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
  5092. end
  5093. def test_create_as_copy_to_a_different_project_should_copy_subtask_custom_fields
  5094. issue = Issue.generate! {|i| i.custom_field_values = {'2' => 'Foo'}}
  5095. child = Issue.generate!(:parent_issue_id => issue.id) {|i| i.custom_field_values = {'2' => 'Bar'}}
  5096. @request.session[:user_id] = 1
  5097. assert_difference 'Issue.count', 2 do
  5098. post(
  5099. :create,
  5100. :params => {
  5101. :project_id => 'ecookbook',
  5102. :copy_from => issue.id,
  5103. :issue => {
  5104. :project_id => '2',
  5105. :tracker_id => 1,
  5106. :status_id => '1',
  5107. :subject => 'Copy with subtasks',
  5108. :custom_field_values => {
  5109. '2' => 'Foo'
  5110. }
  5111. },
  5112. :copy_subtasks => '1'
  5113. }
  5114. )
  5115. end
  5116. child_copy, issue_copy = Issue.order(:id => :desc).limit(2).to_a
  5117. assert_equal 2, issue_copy.project_id
  5118. assert_equal 'Foo', issue_copy.custom_field_value(2)
  5119. assert_equal 'Bar', child_copy.custom_field_value(2)
  5120. end
  5121. def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
  5122. @request.session[:user_id] = 2
  5123. issue = Issue.generate_with_descendants!
  5124. assert_difference 'Issue.count', 1 do
  5125. post(
  5126. :create,
  5127. :params => {
  5128. :project_id => 1,
  5129. :copy_from => 3,
  5130. :issue => {
  5131. :project_id => '1',
  5132. :tracker_id => '3',
  5133. :status_id => '1',
  5134. :subject => 'Copy with subtasks'
  5135. }
  5136. }
  5137. )
  5138. end
  5139. copy = Issue.where(:parent_id => nil).order('id DESC').first
  5140. assert_equal 0, copy.descendants.count
  5141. end
  5142. def test_create_as_copy_with_failure
  5143. @request.session[:user_id] = 2
  5144. post(
  5145. :create,
  5146. :params => {
  5147. :project_id => 1,
  5148. :copy_from => 1,
  5149. :issue => {
  5150. :project_id => '2',
  5151. :tracker_id => '3',
  5152. :status_id => '1',
  5153. :subject => ''
  5154. }
  5155. }
  5156. )
  5157. assert_response :success
  5158. assert_select 'form#issue-form[action="/projects/ecookbook/issues"]' do
  5159. assert_select 'select[name=?]', 'issue[project_id]' do
  5160. assert_select 'option[value="1"]:not([selected])', :text => 'eCookbook'
  5161. assert_select 'option[value="2"][selected=selected]', :text => 'OnlineStore'
  5162. end
  5163. assert_select 'input[name=copy_from][value="1"]'
  5164. end
  5165. end
  5166. def test_create_as_copy_on_project_without_permission_should_ignore_target_project
  5167. @request.session[:user_id] = 2
  5168. assert !User.find(2).member_of?(Project.find(4))
  5169. assert_difference 'Issue.count' do
  5170. post(
  5171. :create,
  5172. :params => {
  5173. :project_id => 1,
  5174. :copy_from => 1,
  5175. :issue => {
  5176. :project_id => '4',
  5177. :tracker_id => '3',
  5178. :status_id => '1',
  5179. :subject => 'Copy'
  5180. }
  5181. }
  5182. )
  5183. end
  5184. issue = Issue.order('id DESC').first
  5185. assert_equal 1, issue.project_id
  5186. end
  5187. def test_create_as_copy_with_watcher_user_ids_should_copy_watchers
  5188. @request.session[:user_id] = 2
  5189. copied = Issue.generate!
  5190. copied.add_watcher User.find(2)
  5191. copied.add_watcher User.find(3)
  5192. assert_difference 'Issue.count' do
  5193. post(
  5194. :create,
  5195. :params => {
  5196. :project_id => 1,
  5197. :copy_from => copied.id,
  5198. :issue => {
  5199. :subject => 'Copy cleared watchers',
  5200. :watcher_user_ids => ['', '3', '10']
  5201. }
  5202. }
  5203. )
  5204. end
  5205. issue = Issue.order('id DESC').first
  5206. assert_equal [3, 10], issue.watcher_user_ids.sort
  5207. end
  5208. def test_create_as_copy_without_watcher_user_ids_should_not_copy_watchers
  5209. @request.session[:user_id] = 2
  5210. copied = Issue.generate!
  5211. copied.add_watcher User.find(2)
  5212. copied.add_watcher User.find(3)
  5213. assert_difference 'Issue.count' do
  5214. post(
  5215. :create,
  5216. :params => {
  5217. :project_id => 1,
  5218. :copy_from => copied.id,
  5219. :issue => {
  5220. :subject => 'Copy cleared watchers',
  5221. :watcher_user_ids => ['']
  5222. }
  5223. }
  5224. )
  5225. end
  5226. issue = Issue.order('id DESC').first
  5227. assert_equal [], issue.watcher_user_ids
  5228. end
  5229. def test_get_edit
  5230. @request.session[:user_id] = 2
  5231. get(:edit, :params => {:id => 1})
  5232. assert_response :success
  5233. assert_select 'select[name=?]', 'issue[project_id]'
  5234. # Be sure we don't display inactive IssuePriorities
  5235. assert_not IssuePriority.find(15).active?
  5236. assert_select 'select[name=?]', 'issue[priority_id]' do
  5237. assert_select 'option[value="15"]', 0
  5238. end
  5239. assert_select 'span.icon-warning', 0
  5240. end
  5241. def test_edit_should_hide_project_if_user_is_not_allowed_to_change_project
  5242. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5243. :field_name => 'project_id', :rule => 'readonly')
  5244. @request.session[:user_id] = 2
  5245. get(:edit, :params => {:id => 1})
  5246. assert_response :success
  5247. assert_select 'select[name=?]', 'issue[project_id]', 0
  5248. end
  5249. def test_new_should_hide_project_if_user_is_not_allowed_to_change_project_in_hierarchy_projects
  5250. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5251. :field_name => 'project_id', :rule => 'readonly')
  5252. @request.session[:user_id] = 2
  5253. get(:new, :params => { :tracker_id => 1, :project_id => 1 })
  5254. assert_response :success
  5255. assert_select 'select[name=?]', 'issue[project_id]', 0
  5256. end
  5257. def test_new_should_show_project_if_user_is_not_allowed_to_change_project_global_new_issue
  5258. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5259. :field_name => 'project_id', :rule => 'readonly')
  5260. @request.session[:user_id] = 2
  5261. get(:new, :params => { :tracker_id => 1})
  5262. assert_response :success
  5263. assert_select 'select[name=?]', 'issue[project_id]'
  5264. end
  5265. def test_edit_should_not_hide_project_when_user_changes_the_project_even_if_project_is_readonly_on_target_project
  5266. WorkflowPermission.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
  5267. :field_name => 'project_id', :rule => 'readonly')
  5268. issue = Issue.generate!(:project_id => 2)
  5269. @request.session[:user_id] = 2
  5270. get(
  5271. :edit,
  5272. :params => {
  5273. :id => issue.id,
  5274. :issue => {
  5275. :project_id => 1
  5276. }
  5277. }
  5278. )
  5279. assert_response :success
  5280. assert_select 'select[name=?]', 'issue[project_id]'
  5281. end
  5282. def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
  5283. @request.session[:user_id] = 2
  5284. Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
  5285. get(:edit, :params => {:id => 1})
  5286. assert_select 'input[name=?]', 'time_entry[hours]'
  5287. end
  5288. def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
  5289. @request.session[:user_id] = 2
  5290. Role.find_by_name('Manager').remove_permission! :log_time
  5291. get(:edit, :params => {:id => 1})
  5292. assert_select 'input[name=?]', 'time_entry[hours]', 0
  5293. end
  5294. def test_get_edit_with_params
  5295. @request.session[:user_id] = 2
  5296. get(
  5297. :edit,
  5298. :params => {
  5299. :id => 1,
  5300. :issue => {
  5301. :status_id => 5,
  5302. :priority_id => 7
  5303. },
  5304. :time_entry => {
  5305. :hours => '2:30',
  5306. :comments => 'test_get_edit_with_params',
  5307. :activity_id => 10
  5308. }
  5309. }
  5310. )
  5311. assert_response :success
  5312. assert_select 'select[name=?]', 'issue[status_id]' do
  5313. assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
  5314. end
  5315. assert_select 'select[name=?]', 'issue[priority_id]' do
  5316. assert_select 'option[value="7"][selected=selected]', :text => 'Urgent'
  5317. end
  5318. assert_select 'input[name=?][value="2:30"]', 'time_entry[hours]'
  5319. assert_select 'select[name=?]', 'time_entry[activity_id]' do
  5320. assert_select 'option[value="10"][selected=selected]', :text => 'Development'
  5321. end
  5322. assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
  5323. end
  5324. def test_get_edit_with_multi_custom_field
  5325. field = CustomField.find(1)
  5326. field.update_attribute :multiple, true
  5327. issue = Issue.find(1)
  5328. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  5329. issue.save!
  5330. @request.session[:user_id] = 2
  5331. get(:edit, :params => {:id => 1})
  5332. assert_response :success
  5333. assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
  5334. assert_select 'option', 3
  5335. assert_select 'option[value=MySQL][selected=selected]'
  5336. assert_select 'option[value=Oracle][selected=selected]'
  5337. assert_select 'option[value=PostgreSQL]:not([selected])'
  5338. end
  5339. end
  5340. def test_get_edit_with_me_assigned_to_id
  5341. @request.session[:user_id] = 2
  5342. get(
  5343. :edit,
  5344. :params => {
  5345. :id => 1,
  5346. :issue => {:assigned_to_id => 'me'}
  5347. }
  5348. )
  5349. assert_response :success
  5350. assert_select 'select[name=?]', 'issue[assigned_to_id]' do
  5351. assert_select 'option[value="2"][selected=selected]'
  5352. end
  5353. end
  5354. def test_get_edit_for_issue_with_transition_warning_should_show_the_warning
  5355. @request.session[:user_id] = 2
  5356. get(
  5357. :edit,
  5358. :params => {
  5359. :id => 9,
  5360. }
  5361. )
  5362. assert_response :success
  5363. reason = l(:notice_issue_not_closable_by_blocking_issue)
  5364. assert_select 'span.icon-warning[title=?]', reason, :text => reason
  5365. end
  5366. def test_get_edit_should_display_visible_spent_time_custom_field
  5367. @request.session[:user_id] = 2
  5368. get(
  5369. :edit,
  5370. :params => {
  5371. :id => 13,
  5372. }
  5373. )
  5374. assert_response :success
  5375. assert_select '#issue-form select.cf_10', 1
  5376. end
  5377. def test_get_edit_should_not_display_spent_time_custom_field_not_visible
  5378. cf = TimeEntryCustomField.find(10)
  5379. cf.visible = false
  5380. cf.role_ids = [1]
  5381. cf.save!
  5382. @request.session[:user_id] = 2
  5383. get(
  5384. :edit,
  5385. :params => {
  5386. :id => 13,
  5387. }
  5388. )
  5389. assert_response :success
  5390. assert_select '#issue-form select.cf_10', 0
  5391. end
  5392. def test_update_form_for_existing_issue
  5393. @request.session[:user_id] = 2
  5394. patch(
  5395. :edit,
  5396. :params => {
  5397. :id => 1,
  5398. :issue => {
  5399. :tracker_id => 2,
  5400. :subject => 'This is the test_new issue',
  5401. :description => 'This is the description',
  5402. :priority_id => 5
  5403. }
  5404. },
  5405. :xhr => true
  5406. )
  5407. assert_response :success
  5408. assert_equal 'text/javascript', response.media_type
  5409. assert_include 'This is the test_new issue', response.body
  5410. end
  5411. def test_update_form_for_existing_issue_should_keep_issue_author
  5412. @request.session[:user_id] = 3
  5413. patch(
  5414. :edit,
  5415. :params => {
  5416. :id => 1,
  5417. :issue => {
  5418. :subject => 'Changed'
  5419. }
  5420. }
  5421. )
  5422. assert_response :success
  5423. assert_equal User.find(2), Issue.find(1).author
  5424. end
  5425. def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
  5426. @request.session[:user_id] = 2
  5427. WorkflowTransition.delete_all
  5428. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
  5429. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
  5430. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
  5431. patch(
  5432. :edit,
  5433. :params => {
  5434. :id => 2,
  5435. :issue => {
  5436. :tracker_id => 2,
  5437. :status_id => 5,
  5438. :subject => 'This is an issue'
  5439. }
  5440. }
  5441. )
  5442. assert_select 'select[name=?]', 'issue[status_id]' do
  5443. assert_select 'option[value="1"]'
  5444. assert_select 'option[value="2"]'
  5445. assert_select 'option[value="5"][selected=selected]'
  5446. assert_select 'option', 3
  5447. end
  5448. end
  5449. def test_update_form_for_existing_issue_with_project_change
  5450. @request.session[:user_id] = 2
  5451. patch(
  5452. :edit,
  5453. :params => {
  5454. :id => 1,
  5455. :issue => {
  5456. :project_id => 2,
  5457. :tracker_id => 2,
  5458. :subject => 'This is the test_new issue',
  5459. :description => 'This is the description',
  5460. :priority_id => 5
  5461. }
  5462. }
  5463. )
  5464. assert_response :success
  5465. assert_select 'select[name=?]', 'issue[project_id]' do
  5466. assert_select 'option[value="2"][selected=selected]'
  5467. end
  5468. assert_select 'select[name=?]', 'issue[tracker_id]' do
  5469. assert_select 'option[value="2"][selected=selected]'
  5470. end
  5471. assert_select 'input[name=?][value=?]', 'issue[subject]', 'This is the test_new issue'
  5472. end
  5473. def test_update_form_should_keep_category_with_same_when_changing_project
  5474. source = Project.generate!
  5475. target = Project.generate!
  5476. source_category = IssueCategory.create!(:name => 'Foo', :project => source)
  5477. target_category = IssueCategory.create!(:name => 'Foo', :project => target)
  5478. issue = Issue.generate!(:project => source, :category => source_category)
  5479. @request.session[:user_id] = 1
  5480. patch(
  5481. :edit,
  5482. :params => {
  5483. :id => issue.id,
  5484. :issue => {
  5485. :project_id => target.id,
  5486. :category_id => source_category.id
  5487. }
  5488. }
  5489. )
  5490. assert_response :success
  5491. assert_select 'select[name=?]', 'issue[category_id]' do
  5492. assert_select 'option[value=?][selected=selected]', target_category.id.to_s
  5493. end
  5494. end
  5495. def test_update_form_should_propose_default_status_for_existing_issue
  5496. @request.session[:user_id] = 2
  5497. WorkflowTransition.delete_all
  5498. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
  5499. patch(:edit, :params => {:id => 2})
  5500. assert_response :success
  5501. assert_select 'select[name=?]', 'issue[status_id]' do
  5502. assert_select 'option[value="2"]'
  5503. assert_select 'option[value="3"]'
  5504. assert_select 'option', 2
  5505. end
  5506. end
  5507. def test_put_update_without_custom_fields_param
  5508. @request.session[:user_id] = 2
  5509. issue = Issue.find(1)
  5510. assert_equal '125', issue.custom_value_for(2).value
  5511. assert_difference('Journal.count') do
  5512. assert_difference('JournalDetail.count') do
  5513. put(
  5514. :update,
  5515. :params => {
  5516. :id => 1,
  5517. :issue => {
  5518. :subject => 'New subject'
  5519. }
  5520. }
  5521. )
  5522. end
  5523. end
  5524. assert_redirected_to :action => 'show', :id => '1'
  5525. issue.reload
  5526. assert_equal 'New subject', issue.subject
  5527. # Make sure custom fields were not cleared
  5528. assert_equal '125', issue.custom_value_for(2).value
  5529. end
  5530. def test_put_update_with_project_change
  5531. @request.session[:user_id] = 2
  5532. ActionMailer::Base.deliveries.clear
  5533. with_settings :notified_events => %w(issue_updated) do
  5534. assert_difference('Journal.count') do
  5535. assert_difference('JournalDetail.count', 3) do
  5536. put(
  5537. :update,
  5538. :params => {
  5539. :id => 1,
  5540. :issue => {
  5541. :project_id => '2',
  5542. :tracker_id => '1', # no change
  5543. :priority_id => '6',
  5544. :category_id => '3'
  5545. }
  5546. }
  5547. )
  5548. end
  5549. end
  5550. end
  5551. assert_redirected_to :action => 'show', :id => '1'
  5552. issue = Issue.find(1)
  5553. assert_equal 2, issue.project_id
  5554. assert_equal 1, issue.tracker_id
  5555. assert_equal 6, issue.priority_id
  5556. assert_equal 3, issue.category_id
  5557. mail = ActionMailer::Base.deliveries.last
  5558. assert_not_nil mail
  5559. assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
  5560. assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
  5561. end
  5562. def test_put_update_trying_to_move_issue_to_project_without_tracker_should_not_error
  5563. target = Project.generate!(:tracker_ids => [])
  5564. assert target.trackers.empty?
  5565. issue = Issue.generate!
  5566. @request.session[:user_id] = 1
  5567. put(
  5568. :update,
  5569. :params => {
  5570. :id => issue.id,
  5571. :issue => {
  5572. :project_id => target.id
  5573. }
  5574. }
  5575. )
  5576. assert_response 302
  5577. end
  5578. def test_put_update_with_tracker_change
  5579. @request.session[:user_id] = 2
  5580. ActionMailer::Base.deliveries.clear
  5581. with_settings :notified_events => %w(issue_updated) do
  5582. assert_difference('Journal.count') do
  5583. assert_difference('JournalDetail.count', 3) do
  5584. put(
  5585. :update,
  5586. :params => {
  5587. :id => 1,
  5588. :issue => {
  5589. :project_id => '1',
  5590. :tracker_id => '2',
  5591. :priority_id => '6'
  5592. }
  5593. }
  5594. )
  5595. end
  5596. end
  5597. end
  5598. assert_redirected_to :action => 'show', :id => '1'
  5599. issue = Issue.find(1)
  5600. assert_equal 1, issue.project_id
  5601. assert_equal 2, issue.tracker_id
  5602. assert_equal 6, issue.priority_id
  5603. assert_equal 1, issue.category_id
  5604. mail = ActionMailer::Base.deliveries.last
  5605. assert_not_nil mail
  5606. assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
  5607. assert_mail_body_match "Tracker changed from Bug to Feature request", mail
  5608. end
  5609. def test_put_update_with_custom_field_change
  5610. @request.session[:user_id] = 2
  5611. issue = Issue.find(1)
  5612. assert_equal '125', issue.custom_value_for(2).value
  5613. with_settings :notified_events => %w(issue_updated) do
  5614. assert_difference('Journal.count') do
  5615. assert_difference('JournalDetail.count', 3) do
  5616. put(
  5617. :update,
  5618. :params => {
  5619. :id => 1,
  5620. :issue => {
  5621. :subject => 'Custom field change',
  5622. :priority_id => '6',
  5623. :category_id => '1', # no change
  5624. :custom_field_values => {'2' => 'New custom value'}
  5625. }
  5626. }
  5627. )
  5628. end
  5629. end
  5630. end
  5631. assert_redirected_to :action => 'show', :id => '1'
  5632. issue.reload
  5633. assert_equal 'New custom value', issue.custom_value_for(2).value
  5634. mail = ActionMailer::Base.deliveries.last
  5635. assert_not_nil mail
  5636. assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
  5637. end
  5638. def test_put_update_with_multi_custom_field_change
  5639. field = CustomField.find(1)
  5640. field.update_attribute :multiple, true
  5641. issue = Issue.find(1)
  5642. issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
  5643. issue.save!
  5644. @request.session[:user_id] = 2
  5645. assert_difference('Journal.count') do
  5646. assert_difference('JournalDetail.count', 3) do
  5647. put(
  5648. :update,
  5649. :params => {
  5650. :id => 1,
  5651. :issue => {
  5652. :subject => 'Custom field change',
  5653. :custom_field_values => {
  5654. '1' => ['', 'Oracle', 'PostgreSQL']
  5655. }
  5656. }
  5657. }
  5658. )
  5659. end
  5660. end
  5661. assert_redirected_to :action => 'show', :id => '1'
  5662. assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
  5663. end
  5664. def test_put_update_with_status_and_assignee_change
  5665. issue = Issue.find(1)
  5666. assert_equal 1, issue.status_id
  5667. @request.session[:user_id] = 2
  5668. with_settings :notified_events => %w(issue_updated) do
  5669. assert_difference('TimeEntry.count', 0) do
  5670. put(
  5671. :update,
  5672. :params => {
  5673. :id => 1,
  5674. :issue => {
  5675. :status_id => 2,
  5676. :assigned_to_id => 3,
  5677. :notes => 'Assigned to dlopper'
  5678. },
  5679. :time_entry => {
  5680. :hours => '',
  5681. :comments => '',
  5682. :activity_id => TimeEntryActivity.first
  5683. }
  5684. }
  5685. )
  5686. end
  5687. end
  5688. assert_redirected_to :action => 'show', :id => '1'
  5689. issue.reload
  5690. assert_equal 2, issue.status_id
  5691. j = Journal.order('id DESC').first
  5692. assert_equal 'Assigned to dlopper', j.notes
  5693. assert_equal 2, j.details.size
  5694. mail = ActionMailer::Base.deliveries.last
  5695. assert_mail_body_match "Status changed from New to Assigned", mail
  5696. # subject should contain the new status
  5697. assert mail.subject.include?("(#{IssueStatus.find(2).name})")
  5698. end
  5699. def test_put_update_with_note_only
  5700. notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
  5701. with_settings :notified_events => %w(issue_updated) do
  5702. # anonymous user
  5703. put(
  5704. :update,
  5705. :params => {
  5706. :id => 1,
  5707. :issue => {
  5708. :notes => notes
  5709. }
  5710. }
  5711. )
  5712. end
  5713. assert_redirected_to :action => 'show', :id => '1'
  5714. j = Journal.order('id DESC').first
  5715. assert_equal notes, j.notes
  5716. assert_equal 0, j.details.size
  5717. assert_equal User.anonymous, j.user
  5718. mail = ActionMailer::Base.deliveries.last
  5719. assert_mail_body_match notes, mail
  5720. end
  5721. def test_put_update_with_private_note_only
  5722. notes = 'Private note'
  5723. @request.session[:user_id] = 2
  5724. assert_difference 'Journal.count' do
  5725. put(
  5726. :update,
  5727. :params => {
  5728. :id => 1,
  5729. :issue => {
  5730. :notes => notes,
  5731. :private_notes => '1'
  5732. }
  5733. }
  5734. )
  5735. assert_redirected_to :action => 'show', :id => '1'
  5736. end
  5737. j = Journal.order('id DESC').first
  5738. assert_equal notes, j.notes
  5739. assert_equal true, j.private_notes
  5740. end
  5741. def test_put_update_with_private_note_and_changes
  5742. notes = 'Private note'
  5743. @request.session[:user_id] = 2
  5744. assert_difference 'Journal.count', 2 do
  5745. put(
  5746. :update,
  5747. :params => {
  5748. :id => 1,
  5749. :issue => {
  5750. :subject => 'New subject',
  5751. :notes => notes,
  5752. :private_notes => '1'
  5753. }
  5754. }
  5755. )
  5756. assert_redirected_to :action => 'show', :id => '1'
  5757. end
  5758. j = Journal.order('id DESC').first
  5759. assert_equal notes, j.notes
  5760. assert_equal true, j.private_notes
  5761. assert_equal 0, j.details.count
  5762. j = Journal.order('id DESC').offset(1).first
  5763. assert_nil j.notes
  5764. assert_equal false, j.private_notes
  5765. assert_equal 1, j.details.count
  5766. end
  5767. def test_put_update_with_note_and_spent_time
  5768. @request.session[:user_id] = 2
  5769. spent_hours_before = Issue.find(1).spent_hours
  5770. assert_difference('TimeEntry.count') do
  5771. put(
  5772. :update,
  5773. :params => {
  5774. :id => 1,
  5775. :issue => {
  5776. :notes => '2.5 hours added'
  5777. },
  5778. :time_entry => {
  5779. :hours => '2.5',
  5780. :comments => 'test_put_update_with_note_and_spent_time',
  5781. :activity_id => TimeEntryActivity.first.id
  5782. }
  5783. }
  5784. )
  5785. end
  5786. assert_redirected_to :action => 'show', :id => '1'
  5787. issue = Issue.find(1)
  5788. j = Journal.order('id DESC').first
  5789. assert_equal '2.5 hours added', j.notes
  5790. assert_equal 0, j.details.size
  5791. t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
  5792. assert_not_nil t
  5793. assert_equal 2.5, t.hours
  5794. assert_equal spent_hours_before + 2.5, issue.spent_hours
  5795. end
  5796. def test_put_update_should_check_add_issue_notes_permission
  5797. role = Role.find(1)
  5798. role.remove_permission! :add_issue_notes
  5799. @request.session[:user_id] = 2
  5800. assert_no_difference 'Journal.count' do
  5801. put(
  5802. :update,
  5803. :params => {
  5804. :id => 1,
  5805. :issue => {
  5806. :notes => 'New note'
  5807. }
  5808. }
  5809. )
  5810. end
  5811. end
  5812. def test_put_update_should_preserve_parent_issue_even_if_not_visible
  5813. parent = Issue.generate!(:project_id => 1, :is_private => true)
  5814. issue = Issue.generate!(:parent_issue_id => parent.id)
  5815. assert !parent.visible?(User.find(3))
  5816. @request.session[:user_id] = 3
  5817. get(:edit, :params => {:id => issue.id})
  5818. assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
  5819. put(
  5820. :update,
  5821. :params => {
  5822. :id => issue.id,
  5823. :issue => {
  5824. :subject => 'New subject',
  5825. :parent_issue_id => parent.id.to_s
  5826. }
  5827. }
  5828. )
  5829. assert_response 302
  5830. assert_equal parent, issue.parent
  5831. end
  5832. def test_put_update_with_attachment_only
  5833. set_tmp_attachments_directory
  5834. # Delete all fixtured journals, a race condition can occur causing the wrong
  5835. # journal to get fetched in the next find.
  5836. Journal.delete_all
  5837. JournalDetail.delete_all
  5838. with_settings :notified_events => %w(issue_updated) do
  5839. # anonymous user
  5840. assert_difference 'Attachment.count' do
  5841. put(
  5842. :update,
  5843. :params => {
  5844. :id => 1,
  5845. :issue => {
  5846. :notes => ''
  5847. },
  5848. :attachments => {
  5849. '1' => {
  5850. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  5851. 'description' => 'test file'
  5852. }
  5853. }
  5854. }
  5855. )
  5856. end
  5857. end
  5858. assert_redirected_to :action => 'show', :id => '1'
  5859. j = Issue.find(1).journals.reorder('id DESC').first
  5860. assert j.notes.blank?
  5861. assert_equal 1, j.details.size
  5862. assert_equal 'testfile.txt', j.details.first.value
  5863. assert_equal User.anonymous, j.user
  5864. attachment = Attachment.order('id DESC').first
  5865. assert_equal Issue.find(1), attachment.container
  5866. assert_equal User.anonymous, attachment.author
  5867. assert_equal 'testfile.txt', attachment.filename
  5868. assert_equal 'text/plain', attachment.content_type
  5869. assert_equal 'test file', attachment.description
  5870. assert_equal 59, attachment.filesize
  5871. assert File.exist?(attachment.diskfile)
  5872. assert_equal 59, File.size(attachment.diskfile)
  5873. mail = ActionMailer::Base.deliveries.last
  5874. assert_mail_body_match 'testfile.txt', mail
  5875. end
  5876. def test_put_update_with_failure_should_save_attachments
  5877. set_tmp_attachments_directory
  5878. @request.session[:user_id] = 2
  5879. assert_no_difference 'Journal.count' do
  5880. assert_difference 'Attachment.count' do
  5881. put(
  5882. :update,
  5883. :params => {
  5884. :id => 1,
  5885. :issue => {
  5886. :subject => ''
  5887. },
  5888. :attachments => {
  5889. '1' => {
  5890. 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
  5891. 'description' => 'test file'
  5892. }
  5893. }
  5894. }
  5895. )
  5896. assert_response :success
  5897. end
  5898. end
  5899. attachment = Attachment.order('id DESC').first
  5900. assert_equal 'testfile.txt', attachment.filename
  5901. assert File.exist?(attachment.diskfile)
  5902. assert_nil attachment.container
  5903. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  5904. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  5905. end
  5906. def test_put_update_with_failure_should_keep_saved_attachments
  5907. set_tmp_attachments_directory
  5908. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  5909. @request.session[:user_id] = 2
  5910. assert_no_difference 'Journal.count' do
  5911. assert_no_difference 'Attachment.count' do
  5912. put(
  5913. :update,
  5914. :params => {
  5915. :id => 1,
  5916. :issue => {
  5917. :subject => ''
  5918. },
  5919. :attachments => {
  5920. 'p0' => {
  5921. 'token' => attachment.token
  5922. }
  5923. }
  5924. }
  5925. )
  5926. assert_response :success
  5927. end
  5928. end
  5929. assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
  5930. assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
  5931. end
  5932. def test_put_update_should_attach_saved_attachments
  5933. set_tmp_attachments_directory
  5934. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  5935. @request.session[:user_id] = 2
  5936. assert_difference 'Journal.count' do
  5937. assert_difference 'JournalDetail.count' do
  5938. assert_no_difference 'Attachment.count' do
  5939. put(
  5940. :update,
  5941. :params => {
  5942. :id => 1,
  5943. :issue => {
  5944. :notes => 'Attachment added'
  5945. },
  5946. :attachments => {
  5947. 'p0' => {
  5948. 'token' => attachment.token
  5949. }
  5950. }
  5951. }
  5952. )
  5953. assert_redirected_to '/issues/1'
  5954. end
  5955. end
  5956. end
  5957. attachment.reload
  5958. assert_equal Issue.find(1), attachment.container
  5959. journal = Journal.order('id DESC').first
  5960. assert_equal 1, journal.details.size
  5961. assert_equal 'testfile.txt', journal.details.first.value
  5962. end
  5963. def test_put_update_with_attachment_that_fails_to_save
  5964. set_tmp_attachments_directory
  5965. # anonymous user
  5966. with_settings :attachment_max_size => 0 do
  5967. put(
  5968. :update,
  5969. :params => {
  5970. :id => 1,
  5971. :issue => {
  5972. :notes => ''
  5973. },
  5974. :attachments => {
  5975. '1' => {
  5976. 'file' => uploaded_test_file('testfile.txt', 'text/plain')
  5977. }
  5978. }
  5979. }
  5980. )
  5981. assert_redirected_to :action => 'show', :id => '1'
  5982. assert_equal '1 file(s) could not be saved.', flash[:warning]
  5983. end
  5984. end
  5985. def test_put_update_with_attachment_deletion_should_create_a_single_journal
  5986. set_tmp_attachments_directory
  5987. ActionMailer::Base.deliveries.clear
  5988. @request.session[:user_id] = 2
  5989. journal = new_record(Journal) do
  5990. assert_difference 'Attachment.count', -2 do
  5991. put(
  5992. :update,
  5993. :params => {
  5994. :id => 3,
  5995. :issue => {
  5996. :notes => 'Removing attachments',
  5997. :deleted_attachment_ids => ['1', '5']
  5998. }
  5999. }
  6000. )
  6001. end
  6002. end
  6003. assert_equal 'Removing attachments', journal.notes
  6004. assert_equal 2, journal.details.count
  6005. assert_select_email do
  6006. assert_select 'ul.journal.details li', 2
  6007. assert_select 'del', :text => 'error281.txt'
  6008. assert_select 'del', :text => 'changeset_iso8859-1.diff'
  6009. end
  6010. end
  6011. def test_put_update_with_attachment_deletion_and_failure_should_preserve_selected_attachments
  6012. set_tmp_attachments_directory
  6013. @request.session[:user_id] = 2
  6014. assert_no_difference 'Journal.count' do
  6015. assert_no_difference 'Attachment.count' do
  6016. put(
  6017. :update,
  6018. :params => {
  6019. :id => 3,
  6020. :issue => {
  6021. :subject => '',
  6022. :notes => 'Removing attachments',
  6023. :deleted_attachment_ids => ['1', '5']
  6024. }
  6025. }
  6026. )
  6027. end
  6028. end
  6029. assert_select 'input[name=?][value="1"][checked=checked]', 'issue[deleted_attachment_ids][]'
  6030. assert_select 'input[name=?][value="5"][checked=checked]', 'issue[deleted_attachment_ids][]'
  6031. assert_select 'input[name=?][value="6"]:not([checked])', 'issue[deleted_attachment_ids][]'
  6032. end
  6033. def test_put_update_with_no_change
  6034. issue = Issue.find(1)
  6035. issue.journals.clear
  6036. ActionMailer::Base.deliveries.clear
  6037. put(
  6038. :update,
  6039. :params => {
  6040. :id => 1,
  6041. :issue => {
  6042. :notes => ''
  6043. }
  6044. }
  6045. )
  6046. assert_redirected_to :action => 'show', :id => '1'
  6047. issue.reload
  6048. assert issue.journals.empty?
  6049. # No email should be sent
  6050. assert ActionMailer::Base.deliveries.empty?
  6051. end
  6052. def test_put_update_should_send_a_notification
  6053. @request.session[:user_id] = 2
  6054. ActionMailer::Base.deliveries.clear
  6055. issue = Issue.find(1)
  6056. old_subject = issue.subject
  6057. new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
  6058. with_settings :notified_events => %w(issue_updated) do
  6059. put(
  6060. :update,
  6061. :params => {
  6062. :id => 1,
  6063. :issue => {
  6064. :subject => new_subject,
  6065. :priority_id => '6',
  6066. :category_id => '1' # no change
  6067. }
  6068. }
  6069. )
  6070. assert_equal 2, ActionMailer::Base.deliveries.size
  6071. end
  6072. end
  6073. def test_put_update_with_invalid_spent_time_hours_only
  6074. @request.session[:user_id] = 2
  6075. notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
  6076. assert_no_difference('Journal.count') do
  6077. put(
  6078. :update,
  6079. :params => {
  6080. :id => 1,
  6081. :issue => {
  6082. :notes => notes
  6083. },
  6084. :time_entry => {
  6085. "comments"=>"", "activity_id"=>"", "hours"=>"2z"
  6086. }
  6087. }
  6088. )
  6089. end
  6090. assert_response :success
  6091. assert_select_error /Activity cannot be blank/
  6092. assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
  6093. assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
  6094. end
  6095. def test_put_update_with_invalid_spent_time_comments_only
  6096. @request.session[:user_id] = 2
  6097. notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
  6098. assert_no_difference('Journal.count') do
  6099. put(
  6100. :update,
  6101. :params => {
  6102. :id => 1,
  6103. :issue => {
  6104. :notes => notes
  6105. },
  6106. :time_entry => {
  6107. "comments"=>"this is my comment", "activity_id"=>"", "hours"=>""
  6108. }
  6109. }
  6110. )
  6111. end
  6112. assert_response :success
  6113. assert_select_error /Activity cannot be blank/
  6114. assert_select_error /Hours cannot be blank/
  6115. assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
  6116. assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
  6117. end
  6118. def test_put_with_spent_time_when_assigned_to_of_private_issue_is_update_at_the_same_time
  6119. @request.session[:user_id] = 3
  6120. Role.find(2).update! :issues_visibility => 'own'
  6121. private_issue = Issue.find(3)
  6122. assert_difference('TimeEntry.count', 1) do
  6123. put(
  6124. :update,
  6125. params: {
  6126. id: private_issue.id,
  6127. issue: { assigned_to_id: nil },
  6128. time_entry: {
  6129. comments: "add spent time", activity_id: TimeEntryActivity.first.id, hours: 1
  6130. }
  6131. }
  6132. )
  6133. end
  6134. assert_select '#errorExplanation', {text: /Log time is invalid/, count: 0}
  6135. assert_select '#errorExplanation', {text: /Issue is invalid/, count: 0}
  6136. assert_redirected_to action: 'show', id: private_issue.id
  6137. assert_not private_issue.reload.visible?
  6138. end
  6139. def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
  6140. issue = Issue.find(2)
  6141. @request.session[:user_id] = 2
  6142. put(
  6143. :update,
  6144. :params => {
  6145. :id => issue.id,
  6146. :issue => {
  6147. :fixed_version_id => 4
  6148. }
  6149. }
  6150. )
  6151. assert_response :redirect
  6152. issue.reload
  6153. assert_equal 4, issue.fixed_version_id
  6154. assert_not_equal issue.project_id, issue.fixed_version.project_id
  6155. end
  6156. def test_put_update_should_redirect_back_using_the_back_url_parameter
  6157. issue = Issue.find(2)
  6158. @request.session[:user_id] = 2
  6159. put(
  6160. :update,
  6161. :params => {
  6162. :id => issue.id,
  6163. :issue => {
  6164. :fixed_version_id => 4
  6165. },
  6166. :back_url => '/issues'
  6167. }
  6168. )
  6169. assert_response :redirect
  6170. assert_redirected_to '/issues'
  6171. end
  6172. def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  6173. issue = Issue.find(2)
  6174. @request.session[:user_id] = 2
  6175. put(
  6176. :update,
  6177. :params => {
  6178. :id => issue.id,
  6179. :issue => {
  6180. :fixed_version_id => 4
  6181. },
  6182. :back_url => 'http://google.com'
  6183. }
  6184. )
  6185. assert_response :redirect
  6186. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
  6187. end
  6188. def test_put_update_should_redirect_with_previous_and_next_issue_ids_params
  6189. @request.session[:user_id] = 2
  6190. put(
  6191. :update,
  6192. :params => {
  6193. :id => 11,
  6194. :issue => {
  6195. :status_id => 6,
  6196. :notes => 'Notes'
  6197. },
  6198. :prev_issue_id => 8,
  6199. :next_issue_id => 12,
  6200. :issue_position => 2,
  6201. :issue_count => 3
  6202. }
  6203. )
  6204. assert_redirected_to '/issues/11?issue_count=3&issue_position=2&next_issue_id=12&prev_issue_id=8'
  6205. end
  6206. def test_update_with_permission_on_tracker_should_be_allowed
  6207. role = Role.find(1)
  6208. role.set_permission_trackers :edit_issues, [1]
  6209. role.save!
  6210. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :subject => 'Original subject')
  6211. @request.session[:user_id] = 2
  6212. put(
  6213. :update,
  6214. :params => {
  6215. :id => issue.id,
  6216. :issue => {
  6217. :subject => 'Changed subject'
  6218. }
  6219. }
  6220. )
  6221. assert_response 302
  6222. assert_equal 'Changed subject', issue.reload.subject
  6223. end
  6224. def test_update_without_permission_on_tracker_should_be_denied
  6225. role = Role.find(1)
  6226. role.set_permission_trackers :edit_issues, [1]
  6227. role.save!
  6228. issue = Issue.generate!(:project_id => 1, :tracker_id => 2, :subject => 'Original subject')
  6229. @request.session[:user_id] = 2
  6230. put(
  6231. :update,
  6232. :params => {
  6233. :id => issue.id,
  6234. :issue => {
  6235. :subject => 'Changed subject'
  6236. }
  6237. }
  6238. )
  6239. assert_response 302
  6240. assert_equal 'Original subject', issue.reload.subject
  6241. end
  6242. def test_update_with_me_assigned_to_id
  6243. @request.session[:user_id] = 2
  6244. issue = Issue.find(1)
  6245. assert_not_equal 2, issue.assigned_to_id
  6246. put(
  6247. :update,
  6248. :params => {
  6249. :id => issue.id,
  6250. :issue => {
  6251. :assigned_to_id => 'me'
  6252. }
  6253. }
  6254. )
  6255. assert_response 302
  6256. assert_equal 2, issue.reload.assigned_to_id
  6257. end
  6258. def test_update_with_value_of_none_should_set_the_values_to_blank
  6259. @request.session[:user_id] = 2
  6260. issue = Issue.find(1)
  6261. issue.custom_field_values = {1 => 'MySQL'}
  6262. issue.assigned_to_id = 2
  6263. issue.save!
  6264. put(
  6265. :update,
  6266. params: {
  6267. id: issue.id,
  6268. issue: {
  6269. assigned_to_id: 'none',
  6270. category_id: 'none',
  6271. fixed_version_id: 'none',
  6272. custom_field_values: { 1 => '__none__' }
  6273. }
  6274. }
  6275. )
  6276. issue.reload
  6277. assert_nil issue.assigned_to
  6278. assert_nil issue.category
  6279. assert_nil issue.fixed_version
  6280. assert_equal '', issue.custom_field_value(1)
  6281. end
  6282. def test_get_bulk_edit
  6283. @request.session[:user_id] = 2
  6284. get(:bulk_edit, :params => {:ids => [1, 3]})
  6285. assert_response :success
  6286. assert_select 'ul#bulk-selection' do
  6287. assert_select 'li', 2
  6288. assert_select 'li a', :text => 'Bug #1'
  6289. end
  6290. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6291. assert_select 'input[name=?]', 'ids[]', 2
  6292. assert_select 'input[name=?][value="1"][type=hidden]', 'ids[]'
  6293. assert_select 'select[name=?]', 'issue[project_id]'
  6294. assert_select 'input[name=?]', 'issue[parent_issue_id]'
  6295. # Project specific custom field, date type
  6296. field = CustomField.find(9)
  6297. assert !field.is_for_all?
  6298. assert_equal 'date', field.field_format
  6299. assert_select 'input[name=?]', 'issue[custom_field_values][9]'
  6300. # System wide custom field
  6301. assert CustomField.find(1).is_for_all?
  6302. assert_select 'select[name=?]', 'issue[custom_field_values][1]'
  6303. # Be sure we don't display inactive IssuePriorities
  6304. assert_not IssuePriority.find(15).active?
  6305. assert_select 'select[name=?]', 'issue[priority_id]' do
  6306. assert_select 'option[value="15"]', 0
  6307. end
  6308. # Initial form should hide 'follow' button
  6309. assert_select 'input[type=submit]', 1 do
  6310. assert_select '[name=?]', 'commit', 1
  6311. assert_select '[name=?]', 'follow', 0
  6312. end
  6313. end
  6314. end
  6315. test "bulk_edit should show follow button when project is selected" do
  6316. @request.session[:user_id] = 2
  6317. post(
  6318. :bulk_edit,
  6319. :params => {
  6320. :ids => [1, 3],
  6321. :issue => {
  6322. :project_id => 2,
  6323. }
  6324. }
  6325. )
  6326. assert_response :success
  6327. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6328. assert_select 'input[type=submit]', 2 do
  6329. assert_select '[name=?]', 'commit', 1
  6330. assert_select '[name=?]', 'follow', 1
  6331. end
  6332. end
  6333. end
  6334. test "bulk_edit should hide follow button when project is not changed" do
  6335. @request.session[:user_id] = 2
  6336. post(
  6337. :bulk_edit,
  6338. :params => {
  6339. :ids => [1, 3],
  6340. :issue => {
  6341. :project_id => "",
  6342. }
  6343. }
  6344. )
  6345. assert_response :success
  6346. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  6347. assert_select 'input[type=submit]', 1 do
  6348. assert_select '[name=?]', 'commit', 1
  6349. assert_select '[name=?]', 'follow', 0
  6350. end
  6351. end
  6352. end
  6353. def test_get_bulk_edit_on_different_projects
  6354. @request.session[:user_id] = 2
  6355. get(:bulk_edit, :params => {:ids => [1, 2, 6]})
  6356. assert_response :success
  6357. # Can not set issues from different projects as children of an issue
  6358. assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
  6359. # Project specific custom field, date type
  6360. field = CustomField.find(9)
  6361. assert !field.is_for_all?
  6362. assert !field.project_ids.include?(Issue.find(6).project_id)
  6363. assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
  6364. end
  6365. def test_get_bulk_edit_with_user_custom_field
  6366. field =
  6367. IssueCustomField.
  6368. create!(
  6369. :name => 'Tester',
  6370. :field_format => 'user',
  6371. :is_for_all => true,
  6372. :tracker_ids => [1, 2, 3]
  6373. )
  6374. @request.session[:user_id] = 2
  6375. get(:bulk_edit, :params => {:ids => [1, 2]})
  6376. assert_response :success
  6377. assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
  6378. assert_select 'option', Project.find(1).users.count + 3 # "no change" + "none" + "me" options
  6379. end
  6380. end
  6381. def test_get_bulk_edit_with_version_custom_field
  6382. field =
  6383. IssueCustomField.
  6384. create!(
  6385. :name => 'Affected version',
  6386. :field_format => 'version',
  6387. :is_for_all => true,
  6388. :tracker_ids => [1, 2, 3]
  6389. )
  6390. @request.session[:user_id] = 2
  6391. get(:bulk_edit, :params => {:ids => [1, 2]})
  6392. assert_response :success
  6393. assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
  6394. assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
  6395. end
  6396. end
  6397. def test_get_bulk_edit_with_multi_custom_field
  6398. field = CustomField.find(1)
  6399. field.update_attribute :multiple, true
  6400. @request.session[:user_id] = 2
  6401. get(:bulk_edit, :params => {:ids => [1, 3]})
  6402. assert_response :success
  6403. assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
  6404. assert_select 'option', field.possible_values.size + 1 # "none" options
  6405. end
  6406. end
  6407. def test_bulk_edit_should_propose_to_clear_text_custom_fields
  6408. @request.session[:user_id] = 2
  6409. get(:bulk_edit, :params => {:ids => [1, 3]})
  6410. assert_response :success
  6411. assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', '__none__'
  6412. end
  6413. def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
  6414. WorkflowTransition.delete_all
  6415. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6416. :old_status_id => 1, :new_status_id => 1)
  6417. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6418. :old_status_id => 1, :new_status_id => 3)
  6419. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
  6420. :old_status_id => 1, :new_status_id => 4)
  6421. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6422. :old_status_id => 2, :new_status_id => 1)
  6423. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6424. :old_status_id => 2, :new_status_id => 3)
  6425. WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
  6426. :old_status_id => 2, :new_status_id => 5)
  6427. @request.session[:user_id] = 2
  6428. get(:bulk_edit, :params => {:ids => [1, 2]})
  6429. assert_select 'select[name=?]', 'issue[status_id]' do
  6430. assert_select 'option[value=""]'
  6431. assert_select 'option[value="1"]'
  6432. assert_select 'option[value="3"]'
  6433. assert_select 'option', 3 # 2 statuses + "no change" option
  6434. end
  6435. end
  6436. def test_bulk_edit_should_propose_target_project_open_shared_versions
  6437. @request.session[:user_id] = 2
  6438. post(
  6439. :bulk_edit,
  6440. :params => {
  6441. :ids => [1, 2, 6],
  6442. :issue => {
  6443. :project_id => 1
  6444. }
  6445. }
  6446. )
  6447. assert_response :success
  6448. expected_versions = Project.find(1).shared_versions.open.to_a.sort
  6449. assert_select 'select[name=?]', 'issue[fixed_version_id]' do
  6450. expected_versions.each do |version|
  6451. assert_select 'option[value=?]', version.id.to_s
  6452. end
  6453. assert_select 'option[value=""]'
  6454. assert_select 'option[value="none"]'
  6455. assert_select 'option', expected_versions.size + 2
  6456. end
  6457. end
  6458. def test_bulk_edit_should_propose_target_project_categories
  6459. @request.session[:user_id] = 2
  6460. post(
  6461. :bulk_edit,
  6462. :params => {
  6463. :ids => [1, 2, 6],
  6464. :issue => {
  6465. :project_id => 1
  6466. }
  6467. }
  6468. )
  6469. assert_response :success
  6470. expected_categories = Project.find(1).issue_categories.sort
  6471. assert_select 'select[name=?]', 'issue[category_id]' do
  6472. expected_categories.each do |category|
  6473. assert_select 'option[value=?]', category.id.to_s
  6474. end
  6475. assert_select 'option[value=""]'
  6476. assert_select 'option[value="none"]'
  6477. assert_select 'option', expected_categories.size + 2
  6478. end
  6479. end
  6480. def test_bulk_edit_should_only_propose_issues_trackers_custom_fields
  6481. IssueCustomField.delete_all
  6482. field1 = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
  6483. field2 = IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
  6484. @request.session[:user_id] = 2
  6485. issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
  6486. get(
  6487. :bulk_edit,
  6488. :params => {
  6489. :ids => issue_ids
  6490. }
  6491. )
  6492. assert_response :success
  6493. assert_select 'input[name=?]', "issue[custom_field_values][#{field1.id}]"
  6494. assert_select 'input[name=?]', "issue[custom_field_values][#{field2.id}]", 0
  6495. end
  6496. def test_bulk_edit_should_propose_target_tracker_custom_fields
  6497. IssueCustomField.delete_all
  6498. field1 = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
  6499. field2 = IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
  6500. @request.session[:user_id] = 2
  6501. issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
  6502. get(
  6503. :bulk_edit,
  6504. :params => {
  6505. :ids => issue_ids,
  6506. :issue => {
  6507. :tracker_id => 2
  6508. }
  6509. }
  6510. )
  6511. assert_response :success
  6512. assert_select 'input[name=?]', "issue[custom_field_values][#{field1.id}]", 0
  6513. assert_select 'input[name=?]', "issue[custom_field_values][#{field2.id}]"
  6514. end
  6515. def test_bulk_edit_should_warn_about_custom_field_values_about_to_be_cleared
  6516. CustomField.destroy_all
  6517. cleared = IssueCustomField.generate!(:name => 'Cleared',
  6518. :tracker_ids => [2],
  6519. :is_for_all => true)
  6520. CustomValue.create!(:customized => Issue.find(2),
  6521. :custom_field => cleared,
  6522. :value => 'foo')
  6523. not_cleared = IssueCustomField.generate!(:name => 'Not cleared',
  6524. :tracker_ids => [2, 3],
  6525. :is_for_all => true)
  6526. CustomValue.create!(:customized => Issue.find(2),
  6527. :custom_field => not_cleared,
  6528. :value => 'bar')
  6529. @request.session[:user_id] = 2
  6530. get(
  6531. :bulk_edit,
  6532. :params => {
  6533. :ids => [1, 2],
  6534. :issue => {
  6535. :tracker_id => 3
  6536. }
  6537. }
  6538. )
  6539. assert_response :success
  6540. assert_select '.warning', :text => /automatic deletion of values/
  6541. assert_select '.warning span', :text => 'Cleared (1)'
  6542. assert_select '.warning span', :text => /Not cleared/, :count => 0
  6543. end
  6544. def test_bulk_update
  6545. @request.session[:user_id] = 2
  6546. # update issues priority
  6547. post(
  6548. :bulk_update,
  6549. :params => {
  6550. :ids => [1, 2],
  6551. :notes => 'Bulk editing',
  6552. :issue => {
  6553. :priority_id => 7,
  6554. :assigned_to_id => '',
  6555. :custom_field_values => {
  6556. '2' => ''
  6557. }
  6558. }
  6559. }
  6560. )
  6561. assert_response 302
  6562. # check that the issues were updated
  6563. assert_equal [7, 7], Issue.where(:id =>[1, 2]).collect {|i| i.priority.id}
  6564. issue = Issue.find(1)
  6565. journal = issue.journals.reorder('created_on DESC').first
  6566. assert_equal '125', issue.custom_value_for(2).value
  6567. assert_equal 'Bulk editing', journal.notes
  6568. assert_equal 1, journal.details.size
  6569. end
  6570. def test_bulk_update_with_group_assignee
  6571. group = Group.find(11)
  6572. project = Project.find(1)
  6573. project.members << Member.new(:principal => group, :roles => [Role.givable.first])
  6574. @request.session[:user_id] = 2
  6575. # update issues assignee
  6576. with_settings :issue_group_assignment => '1' do
  6577. post(
  6578. :bulk_update,
  6579. :params => {
  6580. :ids => [1, 2],
  6581. :notes => 'Bulk editing',
  6582. :issue => {
  6583. :priority_id => '',
  6584. :assigned_to_id => group.id,
  6585. :custom_field_values => {
  6586. '2' => ''
  6587. }
  6588. }
  6589. }
  6590. )
  6591. assert_response 302
  6592. assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
  6593. end
  6594. end
  6595. def test_bulk_update_on_different_projects
  6596. @request.session[:user_id] = 2
  6597. # update issues priority
  6598. post(
  6599. :bulk_update,
  6600. :params => {
  6601. :ids => [1, 2, 6],
  6602. :notes => 'Bulk editing',
  6603. :issue => {
  6604. :priority_id => 7,
  6605. :assigned_to_id => '',
  6606. :custom_field_values => {
  6607. '2' => ''
  6608. }
  6609. }
  6610. }
  6611. )
  6612. assert_response 302
  6613. # check that the issues were updated
  6614. assert_equal [7, 7, 7], Issue.find([1, 2, 6]).map(&:priority_id)
  6615. issue = Issue.find(1)
  6616. journal = issue.journals.reorder('created_on DESC').first
  6617. assert_equal '125', issue.custom_value_for(2).value
  6618. assert_equal 'Bulk editing', journal.notes
  6619. assert_equal 1, journal.details.size
  6620. end
  6621. def test_bulk_update_on_different_projects_without_rights
  6622. @request.session[:user_id] = 3
  6623. user = User.find(3)
  6624. action = {:controller => "issues", :action => "bulk_update"}
  6625. assert user.allowed_to?(action, Issue.find(1).project)
  6626. assert_not user.allowed_to?(action, Issue.find(6).project)
  6627. post(
  6628. :bulk_update,
  6629. :params => {
  6630. :ids => [1, 6],
  6631. :notes => 'Bulk should fail',
  6632. :issue => {
  6633. :priority_id => 7,
  6634. :assigned_to_id => '',
  6635. :custom_field_values => {
  6636. '2' => ''
  6637. }
  6638. }
  6639. }
  6640. )
  6641. assert_response 403
  6642. assert_not_equal "Bulk should fail", Journal.last.notes
  6643. end
  6644. def test_bulk_update_should_send_a_notification
  6645. @request.session[:user_id] = 2
  6646. ActionMailer::Base.deliveries.clear
  6647. with_settings :notified_events => %w(issue_updated) do
  6648. post(
  6649. :bulk_update,
  6650. :params => {
  6651. :ids => [1, 2],
  6652. :notes => 'Bulk editing',
  6653. :issue => {
  6654. :priority_id => 7,
  6655. :assigned_to_id => '',
  6656. :custom_field_values => {'2' => ''}
  6657. }
  6658. }
  6659. )
  6660. assert_response 302
  6661. # 4 emails for 2 members and 2 issues
  6662. # 1 email for a watcher of issue #2
  6663. assert_equal 5, ActionMailer::Base.deliveries.size
  6664. end
  6665. end
  6666. def test_bulk_update_project
  6667. @request.session[:user_id] = 2
  6668. post(
  6669. :bulk_update,
  6670. :params => {
  6671. :ids => [1, 2],
  6672. :issue => {
  6673. :project_id => '2'
  6674. }
  6675. }
  6676. )
  6677. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6678. # Issues moved to project 2
  6679. assert_equal 2, Issue.find(1).project_id
  6680. assert_equal 2, Issue.find(2).project_id
  6681. # No tracker change
  6682. assert_equal 1, Issue.find(1).tracker_id
  6683. assert_equal 2, Issue.find(2).tracker_id
  6684. end
  6685. def test_bulk_update_project_on_single_issue_should_follow_when_needed
  6686. @request.session[:user_id] = 2
  6687. post(
  6688. :bulk_update,
  6689. :params => {
  6690. :id => 1,
  6691. :issue => {
  6692. :project_id => '2'
  6693. },
  6694. :follow => '1'
  6695. }
  6696. )
  6697. assert_redirected_to '/issues/1'
  6698. end
  6699. def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
  6700. @request.session[:user_id] = 2
  6701. post(
  6702. :bulk_update,
  6703. :params => {
  6704. :id => [1, 2],
  6705. :issue => {
  6706. :project_id => '2'
  6707. },
  6708. :follow => '1'
  6709. }
  6710. )
  6711. assert_redirected_to '/projects/onlinestore/issues'
  6712. end
  6713. def test_bulk_update_tracker
  6714. @request.session[:user_id] = 2
  6715. post(
  6716. :bulk_update, :params => {
  6717. :ids => [1, 2],
  6718. :issue => {
  6719. :tracker_id => '2'
  6720. }
  6721. }
  6722. )
  6723. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6724. assert_equal 2, Issue.find(1).tracker_id
  6725. assert_equal 2, Issue.find(2).tracker_id
  6726. end
  6727. def test_bulk_update_status
  6728. @request.session[:user_id] = 2
  6729. # update issues priority
  6730. post(
  6731. :bulk_update,
  6732. :params => {
  6733. :ids => [1, 2],
  6734. :notes => 'Bulk editing status',
  6735. :issue => {
  6736. :priority_id => '',
  6737. :assigned_to_id => '',
  6738. :status_id => '5'
  6739. }
  6740. }
  6741. )
  6742. assert_response 302
  6743. issue = Issue.find(1)
  6744. assert issue.closed?
  6745. end
  6746. def test_bulk_update_priority
  6747. @request.session[:user_id] = 2
  6748. post(
  6749. :bulk_update,
  6750. :params => {
  6751. :ids => [1, 2],
  6752. :issue => {
  6753. :priority_id => 6
  6754. }
  6755. }
  6756. )
  6757. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6758. assert_equal 6, Issue.find(1).priority_id
  6759. assert_equal 6, Issue.find(2).priority_id
  6760. end
  6761. def test_bulk_update_with_notes
  6762. @request.session[:user_id] = 2
  6763. post(
  6764. :bulk_update,
  6765. :params => {
  6766. :ids => [1, 2],
  6767. :notes => 'Moving two issues'
  6768. }
  6769. )
  6770. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6771. assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
  6772. assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
  6773. assert_equal false, Issue.find(1).journals.sort_by(&:id).last.private_notes
  6774. assert_equal false, Issue.find(2).journals.sort_by(&:id).last.private_notes
  6775. end
  6776. def test_bulk_update_with_private_notes
  6777. @request.session[:user_id] = 2
  6778. post(
  6779. :bulk_update,
  6780. :params => {
  6781. :ids => [1, 2],
  6782. :notes => 'Moving two issues',
  6783. :issue => {:private_notes => 'true'}
  6784. }
  6785. )
  6786. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6787. assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
  6788. assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
  6789. assert_equal true, Issue.find(1).journals.sort_by(&:id).last.private_notes
  6790. assert_equal true, Issue.find(2).journals.sort_by(&:id).last.private_notes
  6791. end
  6792. def test_bulk_update_parent_id
  6793. IssueRelation.delete_all
  6794. @request.session[:user_id] = 2
  6795. post(
  6796. :bulk_update,
  6797. :params => {
  6798. :ids => [1, 3],
  6799. :notes => 'Bulk editing parent',
  6800. :issue => {
  6801. :priority_id => '',
  6802. :assigned_to_id => '',
  6803. :status_id => '',
  6804. :parent_issue_id => '2'
  6805. }
  6806. }
  6807. )
  6808. assert_response 302
  6809. parent = Issue.find(2)
  6810. assert_equal parent.id, Issue.find(1).parent_id
  6811. assert_equal parent.id, Issue.find(3).parent_id
  6812. assert_equal [1, 3], parent.children.collect(&:id).sort
  6813. end
  6814. def test_bulk_update_estimated_hours
  6815. @request.session[:user_id] = 2
  6816. post(
  6817. :bulk_update,
  6818. :params => {
  6819. :ids => [1, 2],
  6820. :issue => {
  6821. :estimated_hours => 4.25
  6822. }
  6823. }
  6824. )
  6825. assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
  6826. assert_equal 4.25, Issue.find(1).estimated_hours
  6827. assert_equal 4.25, Issue.find(2).estimated_hours
  6828. end
  6829. def test_bulk_update_custom_field
  6830. @request.session[:user_id] = 2
  6831. # update issues priority
  6832. post(
  6833. :bulk_update,
  6834. :params => {
  6835. :ids => [1, 2],
  6836. :notes => 'Bulk editing custom field',
  6837. :issue => {
  6838. :priority_id => '',
  6839. :assigned_to_id => '',
  6840. :custom_field_values => {
  6841. '2' => '777'
  6842. }
  6843. }
  6844. }
  6845. )
  6846. assert_response 302
  6847. issue = Issue.find(1)
  6848. journal = issue.journals.reorder('created_on DESC').first
  6849. assert_equal '777', issue.custom_value_for(2).value
  6850. assert_equal 1, journal.details.size
  6851. assert_equal '125', journal.details.first.old_value
  6852. assert_equal '777', journal.details.first.value
  6853. end
  6854. def test_bulk_update_custom_field_to_blank
  6855. @request.session[:user_id] = 2
  6856. post(
  6857. :bulk_update,
  6858. :params => {
  6859. :ids => [1, 3],
  6860. :notes => 'Bulk editing custom field',
  6861. :issue => {
  6862. :priority_id => '',
  6863. :assigned_to_id => '',
  6864. :custom_field_values => {
  6865. '1' => '__none__'
  6866. }
  6867. }
  6868. }
  6869. )
  6870. assert_response 302
  6871. assert_equal '', Issue.find(1).custom_field_value(1)
  6872. assert_equal '', Issue.find(3).custom_field_value(1)
  6873. end
  6874. def test_bulk_update_multi_custom_field
  6875. field = CustomField.find(1)
  6876. field.update_attribute :multiple, true
  6877. @request.session[:user_id] = 2
  6878. post(
  6879. :bulk_update,
  6880. :params => {
  6881. :ids => [1, 2, 3],
  6882. :notes => 'Bulk editing multi custom field',
  6883. :issue => {
  6884. :priority_id => '',
  6885. :assigned_to_id => '',
  6886. :custom_field_values => {
  6887. '1' => ['MySQL', 'Oracle']
  6888. }
  6889. }
  6890. }
  6891. )
  6892. assert_response 302
  6893. assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
  6894. assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
  6895. # the custom field is not associated with the issue tracker
  6896. assert_nil Issue.find(2).custom_field_value(1)
  6897. end
  6898. def test_bulk_update_multi_custom_field_to_blank
  6899. field = CustomField.find(1)
  6900. field.update_attribute :multiple, true
  6901. @request.session[:user_id] = 2
  6902. post(
  6903. :bulk_update,
  6904. :params => {
  6905. :ids => [1, 3],
  6906. :notes => 'Bulk editing multi custom field',
  6907. :issue => {
  6908. :priority_id => '',
  6909. :assigned_to_id => '',
  6910. :custom_field_values => {
  6911. '1' => ['__none__']
  6912. }
  6913. }
  6914. }
  6915. )
  6916. assert_response 302
  6917. assert_equal [''], Issue.find(1).custom_field_value(1)
  6918. assert_equal [''], Issue.find(3).custom_field_value(1)
  6919. end
  6920. def test_bulk_update_unassign
  6921. assert_not_nil Issue.find(2).assigned_to
  6922. @request.session[:user_id] = 2
  6923. # unassign issues
  6924. post(
  6925. :bulk_update,
  6926. :params => {
  6927. :ids => [1, 2],
  6928. :notes => 'Bulk unassigning',
  6929. :issue => {
  6930. :assigned_to_id => 'none'
  6931. }
  6932. }
  6933. )
  6934. assert_response 302
  6935. # check that the issues were updated
  6936. assert_nil Issue.find(2).assigned_to
  6937. end
  6938. def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
  6939. @request.session[:user_id] = 2
  6940. post(
  6941. :bulk_update,
  6942. :params => {
  6943. :ids => [1, 2],
  6944. :issue => {
  6945. :fixed_version_id => 4
  6946. }
  6947. }
  6948. )
  6949. assert_response :redirect
  6950. issues = Issue.find([1, 2])
  6951. issues.each do |issue|
  6952. assert_equal 4, issue.fixed_version_id
  6953. assert_not_equal issue.project_id, issue.fixed_version.project_id
  6954. end
  6955. end
  6956. def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
  6957. @request.session[:user_id] = 2
  6958. post(
  6959. :bulk_update,
  6960. :params => {
  6961. :ids => [1, 2],
  6962. :back_url => '/issues'
  6963. }
  6964. )
  6965. assert_response :redirect
  6966. assert_redirected_to '/issues'
  6967. end
  6968. def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  6969. @request.session[:user_id] = 2
  6970. post(
  6971. :bulk_update,
  6972. :params => {
  6973. :ids => [1, 2],
  6974. :back_url => 'http://google.com'
  6975. }
  6976. )
  6977. assert_response :redirect
  6978. assert_redirected_to(
  6979. :controller => 'issues', :action => 'index',
  6980. :project_id => Project.find(1).identifier
  6981. )
  6982. end
  6983. def test_bulk_update_with_all_failures_should_show_errors
  6984. @request.session[:user_id] = 2
  6985. post(
  6986. :bulk_update,
  6987. :params => {
  6988. :ids => [1, 2],
  6989. :issue => {
  6990. :start_date => 'foo'
  6991. }
  6992. }
  6993. )
  6994. assert_response :success
  6995. assert_select '#errorExplanation span', :text => 'Failed to save 2 issue(s) on 2 selected: #1, #2.'
  6996. assert_select '#errorExplanation ul li', :text => 'Start date is not a valid date: #1, #2'
  6997. end
  6998. def test_bulk_update_with_some_failures_should_show_errors
  6999. issue1 = Issue.generate!(:start_date => '2013-05-12')
  7000. issue2 = Issue.generate!(:start_date => '2013-05-15')
  7001. issue3 = Issue.generate!
  7002. @request.session[:user_id] = 2
  7003. post(
  7004. :bulk_update,
  7005. :params => {
  7006. :ids => [issue1.id, issue2.id, issue3.id],
  7007. :issue => {
  7008. :due_date => '2013-05-01'
  7009. }
  7010. }
  7011. )
  7012. assert_response :success
  7013. assert_select '#errorExplanation span',
  7014. :text => "Failed to save 2 issue(s) on 3 selected: ##{issue1.id}, ##{issue2.id}."
  7015. assert_select '#errorExplanation ul li',
  7016. :text => "Due date must be greater than start date: ##{issue1.id}, ##{issue2.id}"
  7017. assert_select '#bulk-selection li', 2
  7018. end
  7019. def test_bulk_update_with_failure_should_preserved_form_values
  7020. @request.session[:user_id] = 2
  7021. post(
  7022. :bulk_update,
  7023. :params => {
  7024. :ids => [1, 2],
  7025. :issue => {
  7026. :tracker_id => '2',
  7027. :start_date => 'foo'
  7028. }
  7029. }
  7030. )
  7031. assert_response :success
  7032. assert_select 'select[name=?]', 'issue[tracker_id]' do
  7033. assert_select 'option[value="2"][selected=selected]'
  7034. end
  7035. assert_select 'input[name=?][value=?]', 'issue[start_date]', 'foo'
  7036. end
  7037. def test_get_bulk_copy
  7038. assert_not Issue.find(1).attachments.any?
  7039. assert Issue.find(2).attachments.any?
  7040. assert Issue.find(3).attachments.any?
  7041. @request.session[:user_id] = 2
  7042. get(
  7043. :bulk_edit,
  7044. :params => {
  7045. :ids => [1, 2, 3],
  7046. :copy => '1'
  7047. }
  7048. )
  7049. assert_response :success
  7050. assert_select '#bulk-selection li', 3
  7051. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7052. assert_select 'select[name=?]', 'issue[project_id]' do
  7053. assert_select 'option[value=""]'
  7054. end
  7055. assert_select 'input[name=copy_attachments]'
  7056. end
  7057. end
  7058. test "bulk copy should show follow button when project is selected" do
  7059. @request.session[:user_id] = 2
  7060. post(
  7061. :bulk_edit,
  7062. :params => {
  7063. :ids => [1, 3],
  7064. :issue => {
  7065. :project_id => 2,
  7066. },
  7067. :copy => '1',
  7068. }
  7069. )
  7070. assert_response :success
  7071. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7072. assert_select 'input[type=submit]', 2 do
  7073. assert_select '[name=?]', 'commit', 1
  7074. assert_select '[name=?]', 'follow', 1
  7075. end
  7076. end
  7077. end
  7078. def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
  7079. user = setup_user_with_copy_but_not_add_permission
  7080. @request.session[:user_id] = user.id
  7081. get(
  7082. :bulk_edit,
  7083. :params => {
  7084. :ids => [1, 2, 3],
  7085. :copy => '1'
  7086. }
  7087. )
  7088. assert_response :success
  7089. assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
  7090. assert_select 'select[name=?]', 'issue[project_id]' do
  7091. assert_select 'option[value=""]', 0
  7092. assert_select 'option[value="2"]'
  7093. end
  7094. end
  7095. end
  7096. def test_bulk_copy_to_another_project
  7097. @request.session[:user_id] = 2
  7098. issue_ids = [1, 2]
  7099. assert_difference 'Issue.count', issue_ids.size do
  7100. assert_no_difference 'Project.find(1).issues.count' do
  7101. post(
  7102. :bulk_update,
  7103. :params => {
  7104. :ids => issue_ids,
  7105. :issue => {
  7106. :project_id => '2'
  7107. },
  7108. :copy => '1'
  7109. }
  7110. )
  7111. end
  7112. end
  7113. assert_redirected_to '/projects/ecookbook/issues'
  7114. copies = Issue.order('id DESC').limit(issue_ids.size)
  7115. copies.each do |copy|
  7116. assert_equal 2, copy.project_id
  7117. end
  7118. end
  7119. def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
  7120. user = setup_user_with_copy_but_not_add_permission
  7121. @request.session[:user_id] = user.id
  7122. assert_difference 'Issue.count', 3 do
  7123. post(
  7124. :bulk_update,
  7125. :params => {
  7126. :ids => [1, 2, 3],
  7127. :issue => {
  7128. :project_id => '2'
  7129. },
  7130. :copy => '1'
  7131. }
  7132. )
  7133. assert_response 302
  7134. end
  7135. end
  7136. def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
  7137. user = setup_user_with_copy_but_not_add_permission
  7138. @request.session[:user_id] = user.id
  7139. post(
  7140. :bulk_update,
  7141. :params => {
  7142. :ids => [1, 2, 3],
  7143. :issue => {
  7144. :project_id => ''
  7145. },
  7146. :copy => '1'
  7147. }
  7148. )
  7149. assert_response 403
  7150. end
  7151. def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
  7152. user = setup_user_with_copy_but_not_add_permission
  7153. @request.session[:user_id] = user.id
  7154. post(
  7155. :bulk_update,
  7156. :params => {
  7157. :ids => [1, 2, 3],
  7158. :issue => {
  7159. :project_id => '1'
  7160. },
  7161. :copy => '1'
  7162. }
  7163. )
  7164. assert_response 403
  7165. end
  7166. def test_bulk_copy_should_allow_not_changing_the_issue_attributes
  7167. @request.session[:user_id] = 2
  7168. issues = [
  7169. Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1,
  7170. :priority_id => 2, :subject => 'issue 1', :author_id => 1,
  7171. :assigned_to_id => nil),
  7172. Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2,
  7173. :priority_id => 1, :subject => 'issue 2', :author_id => 2,
  7174. :assigned_to_id => 2)
  7175. ]
  7176. assert_difference 'Issue.count', issues.size do
  7177. post(
  7178. :bulk_update,
  7179. :params => {
  7180. :ids => issues.map(&:id),
  7181. :copy => '1',
  7182. :issue => {
  7183. :project_id => '',
  7184. :tracker_id => '',
  7185. :assigned_to_id => '',
  7186. :status_id => '',
  7187. :start_date => '',
  7188. :due_date => ''
  7189. }
  7190. }
  7191. )
  7192. end
  7193. copies = Issue.order('id DESC').limit(issues.size)
  7194. issues.each do |orig|
  7195. copy = copies.detect {|c| c.subject == orig.subject}
  7196. assert_not_nil copy
  7197. assert_equal orig.project_id, copy.project_id
  7198. assert_equal orig.tracker_id, copy.tracker_id
  7199. assert_equal 1, copy.status_id
  7200. if orig.assigned_to_id
  7201. assert_equal orig.assigned_to_id, copy.assigned_to_id
  7202. else
  7203. assert_nil copy.assigned_to_id
  7204. end
  7205. assert_equal orig.priority_id, copy.priority_id
  7206. end
  7207. end
  7208. def test_bulk_copy_should_allow_changing_the_issue_attributes
  7209. # Fixes random test failure with Mysql
  7210. # where Issue.where(:project_id => 2).limit(2).order('id desc')
  7211. # doesn't return the expected results
  7212. Issue.where("project_id=2").delete_all
  7213. @request.session[:user_id] = 2
  7214. assert_difference 'Issue.count', 2 do
  7215. assert_no_difference 'Project.find(1).issues.count' do
  7216. post(
  7217. :bulk_update,
  7218. :params => {
  7219. :ids => [1, 2],
  7220. :copy => '1',
  7221. :issue => {
  7222. :project_id => '2',
  7223. :tracker_id => '',
  7224. :assigned_to_id => '2',
  7225. :status_id => '1',
  7226. :start_date => '2009-12-01',
  7227. :due_date => '2009-12-31'
  7228. }
  7229. }
  7230. )
  7231. end
  7232. end
  7233. copied_issues = Issue.where(:project_id => 2).limit(2).order('id desc').to_a
  7234. assert_equal 2, copied_issues.size
  7235. copied_issues.each do |issue|
  7236. assert_equal 2, issue.project_id, "Project is incorrect"
  7237. assert_equal 2, issue.assigned_to_id, "Assigned to is incorrect"
  7238. assert_equal 1, issue.status_id, "Status is incorrect"
  7239. assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
  7240. assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
  7241. end
  7242. end
  7243. def test_bulk_copy_should_allow_adding_a_note
  7244. @request.session[:user_id] = 2
  7245. assert_difference 'Issue.count', 1 do
  7246. post(
  7247. :bulk_update,
  7248. :params => {
  7249. :ids => [1],
  7250. :copy => '1',
  7251. :notes => 'Copying one issue',
  7252. :issue => {
  7253. :project_id => '',
  7254. :tracker_id => '',
  7255. :status_id => '3',
  7256. :start_date => '2009-12-01',
  7257. :due_date => '2009-12-31'
  7258. }
  7259. }
  7260. )
  7261. end
  7262. issue = Issue.order('id DESC').first
  7263. assert_equal 1, issue.journals.size
  7264. journal = issue.journals.first
  7265. assert_equal 'Copying one issue', journal.notes
  7266. end
  7267. def test_bulk_copy_should_allow_not_copying_the_attachments
  7268. attachment_count = Issue.find(3).attachments.size
  7269. assert attachment_count > 0
  7270. @request.session[:user_id] = 2
  7271. assert_difference 'Issue.count', 1 do
  7272. assert_no_difference 'Attachment.count' do
  7273. post(
  7274. :bulk_update,
  7275. :params => {
  7276. :ids => [3],
  7277. :copy => '1',
  7278. :copy_attachments => '0',
  7279. :issue => {
  7280. :project_id => ''
  7281. }
  7282. }
  7283. )
  7284. end
  7285. end
  7286. end
  7287. def test_bulk_copy_should_allow_copying_the_attachments
  7288. attachment_count = Issue.find(3).attachments.size
  7289. assert attachment_count > 0
  7290. @request.session[:user_id] = 2
  7291. assert_difference 'Issue.count', 1 do
  7292. assert_difference 'Attachment.count', attachment_count do
  7293. post(
  7294. :bulk_update,
  7295. :params => {
  7296. :ids => [3],
  7297. :copy => '1',
  7298. :copy_attachments => '1',
  7299. :issue => {
  7300. :project_id => ''
  7301. }
  7302. }
  7303. )
  7304. end
  7305. end
  7306. end
  7307. def test_bulk_copy_should_add_relations_with_copied_issues
  7308. @request.session[:user_id] = 2
  7309. assert_difference 'Issue.count', 2 do
  7310. assert_difference 'IssueRelation.count', 2 do
  7311. post(
  7312. :bulk_update,
  7313. :params => {
  7314. :ids => [1, 3],
  7315. :copy => '1',
  7316. :link_copy => '1',
  7317. :issue => {
  7318. :project_id => '1'
  7319. }
  7320. }
  7321. )
  7322. end
  7323. end
  7324. end
  7325. def test_bulk_copy_should_allow_not_copying_the_subtasks
  7326. issue = Issue.generate_with_descendants!
  7327. @request.session[:user_id] = 2
  7328. assert_difference 'Issue.count', 1 do
  7329. post(
  7330. :bulk_update,
  7331. :params => {
  7332. :ids => [issue.id],
  7333. :copy => '1',
  7334. :copy_subtasks => '0',
  7335. :issue => {
  7336. :project_id => ''
  7337. }
  7338. }
  7339. )
  7340. end
  7341. end
  7342. test "bulk copy should allow copying the subtasks" do
  7343. issue = Issue.generate_with_descendants!
  7344. count = issue.descendants.count
  7345. @request.session[:user_id] = 2
  7346. assert_difference 'Issue.count', count + 1 do
  7347. post(
  7348. :bulk_update,
  7349. :params => {
  7350. :ids => [issue.id],
  7351. :copy => '1',
  7352. :copy_subtasks => '1',
  7353. :issue => {
  7354. :project_id => ''
  7355. }
  7356. }
  7357. )
  7358. end
  7359. copy = Issue.where(:parent_id => nil).order("id DESC").first
  7360. assert_equal count, copy.descendants.count
  7361. end
  7362. test "issue bulk copy copy watcher" do
  7363. issue = Issue.find(1)
  7364. Watcher.create!(:watchable => issue, :user => User.find(3))
  7365. Watcher.create!(:watchable => issue, :user => Group.find(10))
  7366. @request.session[:user_id] = 2
  7367. assert_difference 'Issue.count' do
  7368. post(
  7369. :bulk_update,
  7370. :params => {
  7371. :ids => [1],
  7372. :copy => '1',
  7373. :copy_watchers => '1',
  7374. :issue => {
  7375. :project_id => ''
  7376. }
  7377. }
  7378. )
  7379. end
  7380. copy = Issue.order(:id => :desc).first
  7381. assert_equal 2, copy.watchers.count
  7382. assert_equal [3, 10], copy.watcher_user_ids.sort
  7383. end
  7384. def test_bulk_copy_should_not_copy_selected_subtasks_twice
  7385. issue = Issue.generate_with_descendants!
  7386. count = issue.descendants.count
  7387. @request.session[:user_id] = 2
  7388. assert_difference 'Issue.count', count + 1 do
  7389. post(
  7390. :bulk_update,
  7391. :params => {
  7392. :ids => issue.self_and_descendants.map(&:id),
  7393. :copy => '1',
  7394. :copy_subtasks => '1',
  7395. :issue => {
  7396. :project_id => ''
  7397. }
  7398. }
  7399. )
  7400. end
  7401. copy = Issue.where(:parent_id => nil).order("id DESC").first
  7402. assert_equal count, copy.descendants.count
  7403. end
  7404. def test_bulk_copy_to_another_project_should_follow_when_needed
  7405. @request.session[:user_id] = 2
  7406. post(
  7407. :bulk_update,
  7408. :params => {
  7409. :ids => [1],
  7410. :copy => '1',
  7411. :issue => {
  7412. :project_id => 2
  7413. },
  7414. :follow => '1'
  7415. }
  7416. )
  7417. issue = Issue.order('id DESC').first
  7418. assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
  7419. end
  7420. def test_bulk_copy_with_all_failures_should_display_errors
  7421. @request.session[:user_id] = 2
  7422. post(
  7423. :bulk_update,
  7424. :params => {
  7425. :ids => [1, 2],
  7426. :copy => '1',
  7427. :issue => {
  7428. :start_date => 'foo'
  7429. }
  7430. }
  7431. )
  7432. assert_response :success
  7433. end
  7434. def test_destroy_issue_with_no_time_entries_should_delete_the_issues
  7435. set_tmp_attachments_directory
  7436. assert_nil TimeEntry.find_by_issue_id(2)
  7437. @request.session[:user_id] = 2
  7438. assert_difference 'Issue.count', -1 do
  7439. delete(:destroy, :params => {:id => 2})
  7440. end
  7441. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7442. assert_equal 'Successful deletion.', flash[:notice]
  7443. assert_nil Issue.find_by_id(2)
  7444. end
  7445. def test_destroy_issues_with_time_entries_should_show_the_reassign_form
  7446. set_tmp_attachments_directory
  7447. @request.session[:user_id] = 2
  7448. with_settings :timelog_required_fields => [] do
  7449. assert_no_difference 'Issue.count' do
  7450. delete(
  7451. :destroy,
  7452. :params => {
  7453. :ids => [1, 3]
  7454. }
  7455. )
  7456. end
  7457. end
  7458. assert_response :success
  7459. assert_select 'form' do
  7460. assert_select 'input[name=_method][value=delete]'
  7461. assert_select 'input[name=todo][value=destroy]'
  7462. assert_select 'input[name=todo][value=nullify]'
  7463. assert_select 'input[name=todo][value=reassign]'
  7464. end
  7465. end
  7466. def test_destroy_issues_with_time_entries_should_not_show_the_nullify_option_when_issue_is_required_for_time_entries
  7467. set_tmp_attachments_directory
  7468. with_settings :timelog_required_fields => ['issue_id'] do
  7469. @request.session[:user_id] = 2
  7470. assert_no_difference 'Issue.count' do
  7471. delete(
  7472. :destroy,
  7473. :params => {
  7474. :ids => [1, 3]
  7475. }
  7476. )
  7477. end
  7478. assert_response :success
  7479. assert_select 'form' do
  7480. assert_select 'input[name=_method][value=delete]'
  7481. assert_select 'input[name=todo][value=destroy]'
  7482. assert_select 'input[name=todo][value=nullify]', 0
  7483. assert_select 'input[name=todo][value=reassign]'
  7484. end
  7485. end
  7486. end
  7487. def test_destroy_issues_with_time_entries_should_show_hours_on_issues_and_descendants
  7488. parent = Issue.generate_with_child!
  7489. TimeEntry.generate!(:issue => parent)
  7490. TimeEntry.generate!(:issue => parent.children.first)
  7491. leaf = Issue.generate!
  7492. TimeEntry.generate!(:issue => leaf)
  7493. @request.session[:user_id] = 2
  7494. delete(
  7495. :destroy,
  7496. :params => {
  7497. :ids => [parent.id, leaf.id]
  7498. }
  7499. )
  7500. assert_response :success
  7501. assert_select 'p', :text => /3\.00 hours were reported/
  7502. end
  7503. def test_destroy_issues_and_destroy_time_entries
  7504. set_tmp_attachments_directory
  7505. @request.session[:user_id] = 2
  7506. assert_difference 'Issue.count', -2 do
  7507. assert_difference 'TimeEntry.count', -3 do
  7508. delete(
  7509. :destroy,
  7510. :params => {
  7511. :ids => [1, 3],
  7512. :todo => 'destroy'
  7513. }
  7514. )
  7515. end
  7516. end
  7517. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7518. assert_equal 'Successful deletion.', flash[:notice]
  7519. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7520. assert_nil TimeEntry.find_by_id([1, 2])
  7521. end
  7522. def test_destroy_issues_and_assign_time_entries_to_project
  7523. set_tmp_attachments_directory
  7524. @request.session[:user_id] = 2
  7525. with_settings :timelog_required_fields => [] do
  7526. assert_difference 'Issue.count', -2 do
  7527. assert_no_difference 'TimeEntry.count' do
  7528. delete(
  7529. :destroy,
  7530. :params => {
  7531. :ids => [1, 3],
  7532. :todo => 'nullify'
  7533. }
  7534. )
  7535. end
  7536. end
  7537. end
  7538. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7539. assert_equal 'Successful deletion.', flash[:notice]
  7540. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7541. assert_nil TimeEntry.find(1).issue_id
  7542. assert_nil TimeEntry.find(2).issue_id
  7543. end
  7544. def test_destroy_issues_and_reassign_time_entries_to_another_issue
  7545. set_tmp_attachments_directory
  7546. @request.session[:user_id] = 2
  7547. assert_difference 'Issue.count', -2 do
  7548. assert_no_difference 'TimeEntry.count' do
  7549. delete(
  7550. :destroy,
  7551. :params => {
  7552. :ids => [1, 3],
  7553. :todo => 'reassign',
  7554. :reassign_to_id => 2
  7555. }
  7556. )
  7557. end
  7558. end
  7559. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7560. assert_equal 'Successful deletion.', flash[:notice]
  7561. assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
  7562. assert_equal 2, TimeEntry.find(1).issue_id
  7563. assert_equal 2, TimeEntry.find(2).issue_id
  7564. end
  7565. def test_destroy_issues_with_time_entries_should_reassign_time_entries_of_issues_and_descendants
  7566. parent = Issue.generate_with_child!
  7567. TimeEntry.generate!(:issue => parent)
  7568. TimeEntry.generate!(:issue => parent.children.first)
  7569. leaf = Issue.generate!
  7570. TimeEntry.generate!(:issue => leaf)
  7571. target = Issue.generate!
  7572. @request.session[:user_id] = 2
  7573. assert_difference 'Issue.count', -3 do
  7574. assert_no_difference 'TimeEntry.count' do
  7575. delete(
  7576. :destroy,
  7577. :params => {
  7578. :ids => [parent.id, leaf.id],
  7579. :todo => 'reassign',
  7580. :reassign_to_id => target.id
  7581. }
  7582. )
  7583. assert_response 302
  7584. assert_equal 'Successful deletion.', flash[:notice]
  7585. end
  7586. end
  7587. assert_equal 3, target.time_entries.count
  7588. end
  7589. def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
  7590. set_tmp_attachments_directory
  7591. @request.session[:user_id] = 2
  7592. assert_no_difference 'Issue.count' do
  7593. assert_no_difference 'TimeEntry.count' do
  7594. # try to reassign time to an issue of another project
  7595. delete(
  7596. :destroy,
  7597. :params => {
  7598. :ids => [1, 3],
  7599. :todo => 'reassign',
  7600. :reassign_to_id => 4
  7601. }
  7602. )
  7603. end
  7604. end
  7605. assert_response :success
  7606. end
  7607. def test_destroy_issues_and_reassign_time_entries_to_an_issue_to_delete_should_fail
  7608. set_tmp_attachments_directory
  7609. @request.session[:user_id] = 2
  7610. assert_no_difference 'Issue.count' do
  7611. assert_no_difference 'TimeEntry.count' do
  7612. delete(
  7613. :destroy,
  7614. :params => {
  7615. :ids => [1, 3],
  7616. :todo => 'reassign',
  7617. :reassign_to_id => 3
  7618. }
  7619. )
  7620. end
  7621. end
  7622. assert_response :success
  7623. assert_select '#flash_error', :text => I18n.t(:error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted)
  7624. end
  7625. def test_destroy_issues_and_nullify_time_entries_should_fail_when_issue_is_required_for_time_entries
  7626. set_tmp_attachments_directory
  7627. @request.session[:user_id] = 2
  7628. with_settings :timelog_required_fields => ['issue_id'] do
  7629. assert_no_difference 'Issue.count' do
  7630. assert_no_difference 'TimeEntry.count' do
  7631. delete(
  7632. :destroy,
  7633. :params => {
  7634. :ids => [1, 3],
  7635. :todo => 'nullify'
  7636. }
  7637. )
  7638. end
  7639. end
  7640. end
  7641. assert_response :success
  7642. assert_select '#flash_error', :text => 'Issue cannot be blank'
  7643. end
  7644. def test_destroy_issues_from_different_projects
  7645. set_tmp_attachments_directory
  7646. @request.session[:user_id] = 2
  7647. assert_difference 'Issue.count', -3 do
  7648. delete(
  7649. :destroy,
  7650. :params => {
  7651. :ids => [1, 2, 6],
  7652. :todo => 'destroy'
  7653. }
  7654. )
  7655. end
  7656. assert_redirected_to :controller => 'issues', :action => 'index'
  7657. assert_equal 'Successful deletion.', flash[:notice]
  7658. assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
  7659. end
  7660. def test_destroy_child_issue
  7661. parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
  7662. child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
  7663. assert child.is_descendant_of?(parent.reload)
  7664. @request.session[:user_id] = 2
  7665. assert_difference 'Issue.count', -1 do
  7666. delete :destroy, :params => {:id => child.id}
  7667. end
  7668. assert_response :found
  7669. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  7670. parent.reload
  7671. assert_equal 2, parent.journals.count
  7672. get :show, :params => {:id => parent.id}
  7673. assert_response :success
  7674. assert_select 'div#tab-content-history' do
  7675. assert_select 'div[id=?]', "change-#{parent.journals.last.id}" do
  7676. assert_select 'ul.details', :text => "Subtask deleted (##{child.id})"
  7677. end
  7678. end
  7679. end
  7680. def test_destroy_parent_and_child_issues
  7681. parent = Issue.create!(:project_id => 1, :author_id => 1,
  7682. :tracker_id => 1, :subject => 'Parent Issue')
  7683. child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1,
  7684. :subject => 'Child Issue', :parent_issue_id => parent.id)
  7685. assert child.is_descendant_of?(parent.reload)
  7686. @request.session[:user_id] = 2
  7687. assert_difference 'Issue.count', -2 do
  7688. delete(
  7689. :destroy,
  7690. :params => {
  7691. :ids => [parent.id, child.id],
  7692. :todo => 'destroy'
  7693. }
  7694. )
  7695. end
  7696. assert_response 302
  7697. assert_equal 'Successful deletion.', flash[:notice]
  7698. end
  7699. def test_destroy_invalid_should_respond_with_404
  7700. @request.session[:user_id] = 2
  7701. assert_no_difference 'Issue.count' do
  7702. delete(:destroy, :params => {:id => 999})
  7703. end
  7704. assert_response 404
  7705. end
  7706. def test_destroy_with_permission_on_tracker_should_be_allowed
  7707. role = Role.find(1)
  7708. role.set_permission_trackers :delete_issues, [1]
  7709. role.save!
  7710. issue = Issue.generate!(:project_id => 1, :tracker_id => 1)
  7711. @request.session[:user_id] = 2
  7712. assert_difference 'Issue.count', -1 do
  7713. delete(:destroy, :params => {:id => issue.id})
  7714. end
  7715. assert_response 302
  7716. assert_equal 'Successful deletion.', flash[:notice]
  7717. end
  7718. def test_destroy_without_permission_on_tracker_should_be_denied
  7719. role = Role.find(1)
  7720. role.set_permission_trackers :delete_issues, [2]
  7721. role.save!
  7722. issue = Issue.generate!(:project_id => 1, :tracker_id => 1)
  7723. @request.session[:user_id] = 2
  7724. assert_no_difference 'Issue.count' do
  7725. delete(:destroy, :params => {:id => issue.id})
  7726. end
  7727. assert_response 403
  7728. end
  7729. def test_default_search_scope
  7730. get :index
  7731. assert_select 'div#quick-search form' do
  7732. assert_select 'input[name=issues][value="1"][type=hidden]'
  7733. end
  7734. end
  7735. def setup_user_with_copy_but_not_add_permission
  7736. Role.all.each {|r| r.remove_permission! :add_issues}
  7737. Role.find_by_name('Manager').add_permission! :add_issues
  7738. user = User.generate!
  7739. User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
  7740. User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
  7741. user
  7742. end
  7743. def test_cancel_edit_link_for_issue_show_action_should_have_onclick_action
  7744. @request.session[:user_id] = 1
  7745. get(:show, :params => {:id => 1})
  7746. assert_response :success
  7747. assert_select 'a[href=?][onclick=?]', "/issues/1", "$('#update').hide(); return false;", :text => 'Cancel'
  7748. end
  7749. def test_cancel_edit_link_for_issue_edit_action_should_not_have_onclick_action
  7750. @request.session[:user_id] = 1
  7751. get(:edit, :params => {:id => 1})
  7752. assert_response :success
  7753. assert_select 'a[href=?][onclick=?]', "/issues/1", "", :text => 'Cancel'
  7754. end
  7755. def test_show_should_display_author_gravatar_only_when_not_assigned
  7756. issue = Issue.find(1)
  7757. assert_nil issue.assigned_to_id
  7758. @request.session[:user_id] = 1
  7759. with_settings :gravatar_enabled => '1' do
  7760. get :show, :params => {:id => issue.id}
  7761. assert_select 'div.gravatar-with-child' do
  7762. assert_select 'img.gravatar', 1
  7763. end
  7764. end
  7765. end
  7766. def test_show_should_display_author_and_assignee_gravatars_when_assigned
  7767. issue = Issue.find(1)
  7768. issue.assigned_to_id = 2
  7769. issue.save!
  7770. @request.session[:user_id] = 1
  7771. with_settings :gravatar_enabled => '1' do
  7772. get :show, :params => {:id => issue.id}
  7773. assert_select 'div.gravatar-with-child' do
  7774. assert_select 'img.gravatar', 2
  7775. assert_select 'img.gravatar-child', 1
  7776. end
  7777. end
  7778. end
  7779. def test_show_should_be_able_to_link_to_another_journal_attachment_of_the_same_issue
  7780. @request.session[:user_id] = 1
  7781. issue = Issue.find(2)
  7782. attachment = issue.journals.first.attachments.first
  7783. issue.init_journal(User.first, "attachment:#{attachment.filename}")
  7784. issue.save!
  7785. issue.reload
  7786. get :show, params: { id: issue.id }
  7787. assert_select "div#history div#journal-#{issue.journals.last.id}-notes" do
  7788. assert_select "a[href='/attachments/#{attachment.id}']", :text => 'source.rb'
  7789. end
  7790. end
  7791. def test_show_with_thumbnail_macro_should_be_able_to_fetch_image_of_different_journal
  7792. @request.session[:user_id] = 1
  7793. issue = Issue.find(2)
  7794. attachment = Attachment.generate!(filename: 'foo.png', digest: Redmine::Utils.random_hex(32))
  7795. attachment.update(container: issue)
  7796. issue.init_journal(User.first, "{{thumbnail(#{attachment.filename})}}")
  7797. issue.save!
  7798. issue.reload
  7799. get :show, params: { id: issue.id }
  7800. assert_select "div#history div#journal-#{issue.journals.last.id}-notes" do
  7801. assert_select "a.thumbnail[title=?][href='/attachments/#{attachment.id}']", 'foo.png'
  7802. end
  7803. end
  7804. def test_index_should_retrieve_default_query
  7805. query = IssueQuery.find(4)
  7806. IssueQuery.stubs(:default).returns query
  7807. [nil, 1].each do |user_id|
  7808. @request.session[:user_id] = user_id
  7809. get :index
  7810. assert_select 'h2', text: query.name
  7811. get :index, params: { project_id: 1 }
  7812. assert_select 'h2', text: query.name
  7813. end
  7814. end
  7815. def test_index_should_ignore_default_query_with_without_default
  7816. query = IssueQuery.find(4)
  7817. IssueQuery.stubs(:default).returns query
  7818. [nil, 1].each do |user_id|
  7819. @request.session[:user_id] = user_id
  7820. get :index, params: { set_filter: '1', without_default: '1' }
  7821. assert_select 'h2', text: I18n.t(:label_issue_plural)
  7822. get :index, params: { project_id: 1, set_filter: '1', without_default: '1' }
  7823. assert_select 'h2', text: I18n.t(:label_issue_plural)
  7824. end
  7825. end
  7826. def test_index_should_ignore_default_query_with_session_query
  7827. query = IssueQuery.find 4
  7828. IssueQuery.stubs(:default).returns query
  7829. session_query = IssueQuery.find 1
  7830. @request.session[:issue_query] = { id: 1, project_id: 1}
  7831. @request.session[:user_id] = 1
  7832. get :index, params: { project_id: '1' }
  7833. assert_select 'h2', text: session_query.name
  7834. end
  7835. def test_index_global_should_ignore_default_query_with_session_query
  7836. query = IssueQuery.find 4
  7837. IssueQuery.stubs(:default).returns query
  7838. session_query = IssueQuery.find 5
  7839. @request.session[:issue_query] = { id: 5, project_id: nil}
  7840. @request.session[:user_id] = 1
  7841. get :index
  7842. assert_select 'h2', text: session_query.name
  7843. end
  7844. def test_index_should_use_default_query_with_invalid_session_query
  7845. query = IssueQuery.find 4
  7846. IssueQuery.stubs(:default).returns query
  7847. @request.session[:issue_query] = { id: 1, project_id: 1}
  7848. @request.session[:user_id] = 1
  7849. get :index
  7850. assert_select 'h2', text: query.name
  7851. end
  7852. def test_index_should_not_load_default_query_for_api_request
  7853. query = IssueQuery.find 4
  7854. IssueQuery.stubs(:default).returns query
  7855. @request.session[:user_id] = 1
  7856. get :index, params: { format: 'json' }
  7857. assert results = JSON.parse(@response.body)['issues']
  7858. # query filters for tracker_id == 3
  7859. assert results.detect{ |i| i['tracker_id'] != 3 }
  7860. end
  7861. def test_index_should_ignore_user_default_query_if_it_is_invisible
  7862. query = IssueQuery.find(4)
  7863. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7864. query.save!
  7865. # If visible default query
  7866. @request.session[:user_id] = 2
  7867. @request.session[:issue_query] = nil
  7868. User.find(2).pref.update(default_issue_query: query.id)
  7869. get :index
  7870. assert_select 'h2', text: query.name
  7871. # If invisible default query
  7872. @request.session[:user_id] = 3
  7873. @request.session[:issue_query] = nil
  7874. User.find(3).pref.update(default_issue_query: query.id)
  7875. get :index
  7876. assert_select 'h2', text: 'Issues'
  7877. end
  7878. def test_index_should_ignore_project_default_query_if_it_is_not_public
  7879. query = IssueQuery.find(1)
  7880. query.project.update(default_issue_query: query)
  7881. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7882. query.save!
  7883. [User.find(1), User.find(2)].each do |user|
  7884. @request.session[:user_id] = user.id
  7885. @request.session[:issue_query] = nil
  7886. get :index, params: { project_id: query.project.id }
  7887. assert_select 'h2', text: 'Issues'
  7888. end
  7889. end
  7890. def test_index_should_ignore_global_default_query_if_it_is_not_public
  7891. query = IssueQuery.find(1)
  7892. with_settings default_issue_query: query.id do
  7893. query.update(visibility: Query::VISIBILITY_PRIVATE, user_id: 2)
  7894. query.save!
  7895. [User.find(1), User.find(2)].each do |user|
  7896. @request.session[:user_id] = user.id
  7897. @request.session[:issue_query] = nil
  7898. get :index
  7899. assert_select 'h2', text: 'Issues'
  7900. end
  7901. end
  7902. end
  7903. end