All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.src.core.prop.spec.js Maven / Gradle / Ivy

import { Angular } from "../loader";
import { createInjector } from "./di/injector";
import { valueFn } from "../shared/utils";
import { dealoc } from "../shared/jqlite/jqlite";

fdescribe("ngProp*", () => {
  let $compile, $rootScope, compileProvider, $sce;
  let logs = [];

  beforeEach(() => {
    logs = [];
    window.angular = new Angular();
    window.angular
      .module("myModule", ["ng"])
      .decorator("$exceptionHandler", function () {
        return (exception) => {
          logs.push(exception);
          throw new Error(exception);
        };
      });

    let injector = window.angular.bootstrap(document.getElementById("dummy"), [
      "myModule",
      function ($compileProvider) {
        compileProvider = $compileProvider;
      },
    ]);
    $compile = injector.get("$compile");
    $rootScope = injector.get("$rootScope");
    $sce = injector.get("$sce");
  });

  it("should bind boolean properties (input disabled)", () => {
    const element = $compile(
      '',
    )($rootScope);
    expect(element[0].disabled).toBe(false);
    $rootScope.isDisabled = true;
    expect(element[0].disabled).toBe(true);
    $rootScope.isDisabled = false;
    expect(element[0].disabled).toBe(false);
  });

  it("should bind boolean properties (input checked)", () => {
    const element = $compile(
      '',
    )($rootScope);
    expect(element[0].checked).toBe(false);
    $rootScope.isChecked = true;
    expect(element[0].checked).toBe(true);
    $rootScope.isChecked = false;
    expect(element[0].checked).toBe(false);
  });

  it("should bind string properties (title)", () => {
    const element = $compile('')($rootScope);
    $rootScope.title = 123;
    expect(element[0].title).toBe("123");
    $rootScope.title = "foobar";
    expect(element[0].title).toBe("foobar");
  });

  it("should bind variable type properties", () => {
    const element = $compile('')($rootScope);
    $rootScope.asdf = 123;
    expect(element[0].asdf).toBe(123);
    $rootScope.asdf = "foobar";
    expect(element[0].asdf).toBe("foobar");
    $rootScope.asdf = true;
    expect(element[0].asdf).toBe(true);
  });

  // https://github.com/angular/angular.js/issues/16797
  it("should support falsy property values", () => {
    const element = $compile('')($rootScope);
    // Initialize to truthy value
    $rootScope.myText = "abc";
    expect(element[0].text).toBe("abc");

    // Assert various falsey values get assigned to the property
    $rootScope.myText = "";
    expect(element[0].text).toBe("");
    $rootScope.myText = 0;
    expect(element[0].text).toBe(0);
    $rootScope.myText = false;
    expect(element[0].text).toBe(false);
    $rootScope.myText = undefined;
    expect(element[0].text).toBeUndefined();
    $rootScope.myText = null;
    expect(element[0].text).toBe(null);
  });

  it("should directly map special properties (class)", () => {
    const element = $compile('')($rootScope);
    $rootScope.myText = "abc";
    expect(element[0].class).toBe("abc");
    expect(element[0]).not.toHaveClass("abc");
  });

  it("should support mixed case using underscore-separated names", () => {
    const element = $compile('')($rootScope);
    $rootScope.value = 123;
    expect(element[0].aBcdE).toBe(123);
  });

  it("should work with different prefixes", () => {
    $rootScope.name = "Misko";
    const element = $compile(
      '',
    )($rootScope);
    expect(element[0].test).toBe("Misko");
    expect(element[0].test2).toBe("Misko");
    expect(element[0].test3).toBe("Misko");
  });

  it('should work with the "href" property', () => {
    $rootScope.value = "test";
    const element = $compile("")(
      $rootScope,
    );
    expect(element[0].href).toMatch(/\/test\/test$/);
  });

  it("should work if they are prefixed with x- or data- and different prefixes", () => {
    $rootScope.name = "Misko";
    const element = $compile(
      '',
    )($rootScope);
    expect(element[0].test2).toBe("Misko");
    expect(element[0].test3).toBe("Misko");
    expect(element[0].test4).toBe("Misko");
    expect(element[0].test5).toBe("Misko");
    expect(element[0].test6).toBe("Misko");
  });

  it("should work independently of attributes with the same name", () => {
    const element = $compile('')(
      $rootScope,
    );
    $rootScope.asdf = 123;
    expect(element[0].asdf).toBe(123);
    expect(element.attr("asdf")).toBe("foo");
  });

  it("should work independently of (ng-)attributes with the same name", () => {
    const element = $compile('')(
      $rootScope,
    );
    $rootScope.asdf = 123;
    expect(element[0].asdf).toBe(123);
    expect(element.attr("asdf")).toBe("foo");
  });

  it("should use the full ng-prop-* attribute name in $attr mappings", () => {
    let attrs;
    compileProvider.directive(
      "attrExposer",
      valueFn({
        link($scope, $element, $attrs) {
          attrs = $attrs;
        },
      }),
    );
    $compile(
      '
', )($rootScope); expect(attrs.title).toBeUndefined(); expect(attrs.$attr.title).toBeUndefined(); expect(attrs.ngPropTitle).toBe("12"); expect(attrs.$attr.ngPropTitle).toBe("ng-prop-title"); expect(attrs.superTitle).toBeUndefined(); expect(attrs.$attr.superTitle).toBeUndefined(); expect(attrs.ngPropSuperTitle).toBe("34"); expect(attrs.$attr.ngPropSuperTitle).toBe("ng-prop-super-title"); expect(attrs.myCamelTitle).toBeUndefined(); expect(attrs.$attr.myCamelTitle).toBeUndefined(); expect(attrs.ngPropMyCamelTitle).toBe("56"); expect(attrs.$attr.ngPropMyCamelTitle).toBe("ng-prop-my-camel-title"); }); it("should not conflict with (ng-attr-)attribute mappings of the same name", () => { let attrs; compileProvider.directive( "attrExposer", valueFn({ link($scope, $element, $attrs) { attrs = $attrs; }, }), ); $compile( '
', )($rootScope); expect(attrs.title).toBe("foo"); expect(attrs.$attr.title).toBe("title"); expect(attrs.$attr.ngPropTitle).toBe("ng-prop-title"); }); it("should disallow property binding to onclick", () => { // All event prop bindings are disallowed. expect(() => { $compile(''); }).toThrowError(/nodomevents/); expect(() => { $compile(''); }).toThrowError(/nodomevents/); }); it("should process property bindings in pre-linking phase at priority 100", () => { compileProvider.directive("propLog", () => ({ compile($element, $attrs) { logs.push(`compile=${$element[0].myName}`); return { pre($scope, $element, $attrs) { logs.push(`preLinkP0=${$element[0].myName}`); $rootScope.name = "pre0"; }, post($scope, $element, $attrs) { logs.push(`postLink=${$element[0].myName}`); $rootScope.name = "post0"; }, }; }, })); compileProvider.directive("propLogHighPriority", () => ({ priority: 101, compile() { return { pre($scope, $element, $attrs) { logs.push(`preLinkP101=${$element[0].myName}`); $rootScope.name = "pre101"; }, }; }, })); const element = $compile( '
', )($rootScope); $rootScope.name = "loader"; $rootScope.$apply(); logs.push(`digest=${element[0].myName}`); expect(logs.join("; ")).toEqual( "compile=undefined; preLinkP101=undefined; preLinkP0=pre101; postLink=pre101; digest=loader", ); }); describe("img[src] sanitization", () => { it("should accept trusted values", () => { const element = $compile('')($rootScope); // Some browsers complain if you try to write `javascript:` into an `img[src]` // So for the test use something different $rootScope.testUrl = $sce.trustAsMediaUrl("someuntrustedthing:foo();"); expect(element[0].src).toEqual("someuntrustedthing:foo();"); }); it("should use $$sanitizeUri", () => { const $$sanitizeUri = jasmine .createSpy("$$sanitizeUri") .and.returnValue("someSanitizedUrl"); createInjector([ "myModule", ($provide) => { $provide.value("$$sanitizeUri", $$sanitizeUri); }, ]).invoke((_$compile_, _$rootScope_) => { $compile = _$compile_; $rootScope = _$rootScope_; }); const element = $compile('')($rootScope); $rootScope.testUrl = "someUrl"; $rootScope.$apply(); expect(element[0].src).toMatch(/^http:\/\/.*\/someSanitizedUrl$/); expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, true); }); it("should not use $$sanitizeUri with trusted values", () => { const $$sanitizeUri = jasmine .createSpy("$$sanitizeUri") .and.throwError("Should not have been called"); createInjector([ "myModule", ($provide) => { $provide.value("$$sanitizeUri", $$sanitizeUri); }, ]).invoke((_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }); const element = $compile('')($rootScope); // Assigning javascript:foo to src makes at least IE9-11 complain, so use another // protocol name. $rootScope.testUrl = $sce.trustAsMediaUrl("untrusted:foo();"); $rootScope.$apply(); expect(element[0].src).toBe("untrusted:foo();"); }); }); describe("a[href] sanitization", () => { it("should NOT require trusted values for trusted URI values", () => { $rootScope.testUrl = "http://example.com/image.png"; // `http` is trusted let element = $compile('')($rootScope); expect(element[0].href).toEqual("http://example.com/image.png"); element = $compile('')($rootScope); expect(element[0].href).toEqual("http://example.com/image.png"); }); it("should accept trusted values for non-trusted URI values", () => { $rootScope.testUrl = $sce.trustAsUrl("javascript:foo()"); // `javascript` is not trusted let element = $compile('')($rootScope); expect(element[0].href).toEqual("javascript:foo()"); element = $compile('')($rootScope); expect(element[0].href).toEqual("javascript:foo()"); }); it("should sanitize non-trusted values", () => { $rootScope.testUrl = "javascript:foo()"; // `javascript` is not trusted let element = $compile('')($rootScope); expect(element[0].href).toEqual("unsafe:javascript:foo()"); element = $compile('')($rootScope); expect(element[0].href).toEqual("unsafe:javascript:foo()"); }); it("should not sanitize href on elements other than anchor", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = "javascript:doEvilStuff()"; $rootScope.$apply(); expect(element[0].href).toBe("javascript:doEvilStuff()"); }); it("should not sanitize properties other then those configured", () => { const element = $compile('')($rootScope); $rootScope.testUrl = "javascript:doEvilStuff()"; $rootScope.$apply(); expect(element[0].title).toBe("javascript:doEvilStuff()"); }); it("should use $$sanitizeUri", () => { const $$sanitizeUri = jasmine .createSpy("$$sanitizeUri") .and.returnValue("someSanitizedUrl"); createInjector([ "myModule", ($provide) => { $provide.value("$$sanitizeUri", $$sanitizeUri); }, ]).invoke((_$compile_, _$rootScope_) => { $compile = _$compile_; $rootScope = _$rootScope_; }); let element = $compile('')($rootScope); $rootScope.testUrl = "someUrl"; $rootScope.$apply(); expect(element[0].href).toMatch(/^http:\/\/.*\/someSanitizedUrl$/); expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false); $$sanitizeUri.calls.reset(); element = $compile('')($rootScope); $rootScope.$apply(); expect(element[0].href).toMatch(/^http:\/\/.*\/someSanitizedUrl$/); expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false); }); it("should not have endless digests when given arrays in concatenable context", () => { const element = $compile( '' + "", )($rootScope); $rootScope.testUrl = [1]; $rootScope.testUrl = []; $rootScope.testUrl = { a: "b" }; $rootScope.testUrl = {}; }); }); describe("iframe[src]", () => { beforeEach(() => { createInjector(["myModule"]).invoke( (_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }, ); }); it("should pass through src properties for the same domain", () => { const element = $compile('')( $rootScope, ); $rootScope.testUrl = "different_page"; $rootScope.$apply(); expect(element[0].src).toMatch(/\/different_page$/); }); it("should clear out src properties for a different domain", () => { const element = $compile('')( $rootScope, ); $rootScope.testUrl = "http://a.different.domain.example.com"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should clear out JS src properties", () => { const element = $compile('')( $rootScope, ); $rootScope.testUrl = "javascript:alert(1);"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should clear out non-resource_url src properties", () => { const element = $compile('')( $rootScope, ); $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()"); expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should pass through $sce.trustAs() values in src properties", () => { const element = $compile('')( $rootScope, ); $rootScope.testUrl = $sce.trustAsResourceUrl( "javascript:doTrustedStuff()", ); $rootScope.$apply(); expect(element[0].src).toEqual("javascript:doTrustedStuff()"); }); }); describe("base[href]", () => { beforeEach(() => { createInjector(["myModule"]).invoke( (_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }, ); }); it("should be a RESOURCE_URL context", () => { const element = $compile('')($rootScope); $rootScope.testUrl = $sce.trustAsResourceUrl("https://example.com/"); $rootScope.$apply(); expect(element[0].href).toContain("https://example.com/"); $rootScope.testUrl = "https://not.example.com/"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); }); describe("form[action]", () => { beforeEach(() => { createInjector(["myModule"]).invoke( (_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }, ); }); it("should pass through action property for the same domain", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = "different_page"; $rootScope.$apply(); expect(element[0].action).toMatch(/\/different_page$/); }); it("should clear out action property for a different domain", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = "http://a.different.domain.example.com"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should clear out JS action property", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = "javascript:alert(1);"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should clear out non-resource_url action property", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()"); expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should pass through $sce.trustAsResourceUrl() values in action property", () => { const element = $compile('
')( $rootScope, ); $rootScope.testUrl = $sce.trustAsResourceUrl( "javascript:doTrustedStuff()", ); $rootScope.$apply(); expect(element[0].action).toEqual("javascript:doTrustedStuff()"); }); }); describe("link[href]", () => { beforeEach(() => { createInjector(["myModule"]).invoke( (_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }, ); }); it("should reject invalid RESOURCE_URLs", () => { const element = $compile( '', )($rootScope); $rootScope.testUrl = "https://evil.example.org/css.css"; expect(() => { $rootScope.$apply(); }).toThrowError(/insecurl/); }); it("should accept valid RESOURCE_URLs", () => { const element = $compile( '', )($rootScope); $rootScope.testUrl = "./css1.css"; $rootScope.$apply(); expect(element[0].href).toContain("css1.css"); $rootScope.testUrl = $sce.trustAsResourceUrl( "https://elsewhere.example.org/css2.css", ); $rootScope.$apply(); expect(element[0].href).toContain( "https://elsewhere.example.org/css2.css", ); }); }); describe("*[innerHTML]", () => { describe("SCE disabled", () => { beforeEach(() => { dealoc(document.getElementById("dummy")); window.angular .bootstrap(document.getElementById("dummy"), [ "myModule", ($sceProvider) => { $sceProvider.enabled(false); }, ]) .invoke((_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }); }); it("should set html", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = '
hello
'; expect(element.html()).toEqual('
hello
'); }); it("should update html", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = "hello"; expect(element.html()).toEqual("hello"); $rootScope.html = "goodbye"; expect(element.html()).toEqual("goodbye"); }); it("should one-time bind if the expression starts with two colons", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = '
hello
'; expect($rootScope.$$watchers.length).toEqual(1); expect(element.text()).toEqual("hello"); expect($rootScope.$$watchers.length).toEqual(0); $rootScope.html = '
hello
'; expect(element.text()).toEqual("hello"); }); }); describe("SCE enabled", () => { beforeEach(() => { createInjector([ "myModule", ($sceProvider) => { $sceProvider.enabled(true); }, ]).invoke((_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }); }); it("should NOT set html for untrusted values", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = '
hello
'; expect(() => {}).toThrowError(/unsafe/); }); it("should NOT set html for wrongly typed values", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = $sce.trustAsCss('
hello
'); expect(() => {}).toThrowError(/unsafe/); }); it("should set html for trusted values", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = $sce.trustAsHtml('
hello
'); expect(element.html()).toEqual('
hello
'); }); it("should update html", () => { const element = $compile('
')( $rootScope, ); $rootScope.html = $sce.trustAsHtml("hello"); expect(element.html()).toEqual("hello"); $rootScope.html = $sce.trustAsHtml("goodbye"); expect(element.html()).toEqual("goodbye"); }); it("should not cause infinite recursion for trustAsHtml object watches", () => { // Ref: https://github.com/angular/angular.js/issues/3932 // If the binding is a function that creates a new value on every call via trustAs, we'll // trigger an infinite digest if we don't take care of it. const element = $compile( '
', )($rootScope); $rootScope.getHtml = function () { return $sce.trustAsHtml('
hello
'); }; expect(element.html()).toEqual('
hello
'); }); it("should handle custom $sce objects", () => { function MySafeHtml(val) { this.val = val; } createInjector([ "myModule", ($provide) => { $provide.decorator("$sce", ($delegate) => { $delegate.trustAsHtml = function (html) { return new MySafeHtml(html); }; $delegate.getTrusted = function (type, mySafeHtml) { return mySafeHtml && mySafeHtml.val; }; $delegate.valueOf = function (v) { return v instanceof MySafeHtml ? v.val : v; }; return $delegate; }); }, ]).invoke((_$compile_, _$rootScope_, _$sce_) => { $compile = _$compile_; $rootScope = _$rootScope_; $sce = _$sce_; }); // Ref: https://github.com/angular/angular.js/issues/14526 // Previous code used toString for change detection, which fails for custom objects // that don't override toString. const element = $compile( '
', )($rootScope); let html = "hello"; $rootScope.getHtml = function () { return $sce.trustAsHtml(html); }; expect(element.html()).toEqual("hello"); html = "goodbye"; expect(element.html()).toEqual("goodbye"); }); }); }); describe("*[style]", () => { it("should NOT set style for untrusted values", () => { const element = $compile('
')($rootScope); $rootScope.style = "margin-left: 10px"; expect(() => {}).toThrowError(/unsafe/); }); it("should NOT set style for wrongly typed values", () => { const element = $compile('
')($rootScope); $rootScope.style = $sce.trustAsHtml("margin-left: 10px"); expect(() => {}).toThrowError(/unsafe/); }); it("should set style for trusted values", () => { const element = $compile('
')($rootScope); $rootScope.style = $sce.trustAsCss("margin-left: 10px"); expect(element[0].style["margin-left"]).toEqual("10px"); }); }); });




© 2015 - 2025 Weber Informatics LLC | Privacy Policy