module import * as assert from "assert" ; import * as propParser from "css-property-parser" ; import * as parse5 from "parse5" ; import { Cascade , ComputedStyle , ElementStyle , FullCascade , allElements , bodyElement , debugElement , parseHtml , } from "./index" ; export interface AssertionResult { expectedFullCascade : FullCascade ; expectedDoc : parse5 . Document ; expectedCss : string ; actualFullCascade : FullCascade ; actualDoc : parse5 . Document ; actualCss : string ; } export class MarkupMismatchError extends assert . AssertionError { constructor ( actual , expected , message = "html has differing element lengths" ) { super ( { message , actual , expected } ) ; } } export interface CascadeInformation { expectedHtml : string ; actualHtml : string ; expectedElement : string ; actualElement : string ; expectedCss : string ; actualCss : string ; expectedCascade : ElementStyle | undefined ; actualCascade : ElementStyle | undefined ; expectedStyles : ComputedStyle | undefined ; actualStyles : ComputedStyle | undefined ; } export class ElementStyleMismatch extends assert . AssertionError implements CascadeInformation { expectedHtml : string ; actualHtml : string ; expectedElement : string ; actualElement : string ; expectedCss : string ; actualCss : string ; expectedCascade : ElementStyle ; actualCascade : ElementStyle ; expectedStyles : ComputedStyle | undefined ; actualStyles : ComputedStyle | undefined ; constructor ( details , message ? ) { super ( { expected : details . expectedStyles , actual : details . actualStyles , message : message || "Styles do not match." , } ) ; Object . assign ( this , details ) ; } } param property param actualValue param expectedValue export function assertSameStyle ( property , actualValue , expectedValue ) { try { if ( propParser . isInitialValue ( property , expectedValue ) ) { if ( ! propParser . isInitialValue ( property , actualValue ) ) { assert . fail ( `Expected ${ actualValue } to be an initial value for ${ property }.` ) ; } else { return ; } } } catch ( e ) { if ( e instanceof propParser . UnknownPropertyError ) { if ( ! e . property . startsWith ( "-" ) ) { console . log ( e . message ) ; } } else { throw e ; } } expectedValue = expectedValue . toLowerCase ( ) . trim ( ) . replace ( /\s+/g , " " ) ; actualValue = actualValue . toLowerCase ( ) . trim ( ) . replace ( /\s+/g , " " ) ; assert . equal ( actualValue , expectedValue ) ; } export function assertSameCascade ( expectedCss , actualCss , expectedHtml , actualHtml ) { let expectedDoc = parseHtml ( expectedHtml ) ; let expectedFullCascade = new Cascade ( expectedCss , expectedDoc ) ; let actualDoc = parseHtml ( actualHtml ) ; let actualFullCascade = new Cascade ( actualCss , actualDoc ) ; let cascades = [ expectedFullCascade . perform ( ) , actualFullCascade . perform ( ) ] ; return Promise . all ( cascades ) . then ( ( [ expectedFullCascade , actualFullCascade ] ) => { let expectedBody = bodyElement ( expectedDoc ) ! ; let expectedElements = allElements ( expectedBody ) ; let actualBody = bodyElement ( actualDoc ) ! ; let actualElements = allElements ( actualBody ) ; if ( actualElements . length !== expectedElements . length ) { throw new MarkupMismatchError ( expectedHtml , actualHtml ) ; } for ( let i = 0 ; i < expectedElements . length ; i ++ ) { let expectedElement = expectedElements [ i ] ; let actualElement = actualElements [ i ] ; let expectedCascade = expectedFullCascade . get ( expectedElement ) ; let actualCascade = actualFullCascade . get ( actualElement ) ; if ( expectedCascade || actualCascade ) { let expectedStyles = expectedCascade && expectedCascade . compute ( ) ; let actualStyles = actualCascade && actualCascade . compute ( ) ; try { if ( actualStyles && expectedStyles ) { let actualProps = Object . keys ( actualStyles ) . sort ( ) ; let expectedProps = Object . keys ( expectedStyles ) . sort ( ) ; assert . deepEqual ( actualProps , expectedProps ) ; for ( let prop of actualProps ) { assertSameStyle ( prop , actualStyles [ prop ] , expectedStyles [ prop ] ) ; } } else { if ( actualStyles ) { assert . fail ( "Styles were not expected for the element" ) ; } if ( expectedStyles ) { assert . fail ( "Expected styles were not assigned to the element" ) ; } } } catch ( e ) { throw new ElementStyleMismatch ( { expectedHtml , actualHtml , expectedElement : debugElement ( expectedElement ) , actualElement : debugElement ( actualElement ) , expectedCss , actualCss , expectedCascade , actualCascade , expectedStyles , actualStyles , } , e . message ) ; } } } return { expectedFullCascade , expectedDoc , expectedCss , actualFullCascade , actualDoc , actualCss , } ; } ) ; }