diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts
index 3afcd69a2..48ee9a60c 100644
--- a/src/core/components/iframe/iframe.ts
+++ b/src/core/components/iframe/iframe.ts
@@ -32,6 +32,8 @@ import { DomSanitizer } from '@singletons';
})
export class CoreIframeComponent implements OnChanges {
+ static loadingTimeout = 15000;
+
@ViewChild('iframe') iframe?: ElementRef;
@Input() src?: string;
@Input() iframeWidth?: string;
@@ -43,7 +45,6 @@ export class CoreIframeComponent implements OnChanges {
safeUrl?: SafeResourceUrl;
displayHelp = false;
- protected readonly IFRAME_TIMEOUT = 15000;
protected logger: CoreLogger;
protected initialized = false;
@@ -89,7 +90,7 @@ export class CoreIframeComponent implements OnChanges {
if (this.loading) {
setTimeout(() => {
this.loading = false;
- }, this.IFRAME_TIMEOUT);
+ }, CoreIframeComponent.loadingTimeout);
}
}
diff --git a/src/core/components/tests/iframe.test.ts b/src/core/components/tests/iframe.test.ts
index 2b80c90c3..75a0c754d 100644
--- a/src/core/components/tests/iframe.test.ts
+++ b/src/core/components/tests/iframe.test.ts
@@ -12,8 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import { CoreIframeComponent } from '@components/iframe/iframe';
+
+import { renderTemplate } from '@/testing/utils';
+
describe('CoreIframeComponent', () => {
- it.todo('should render');
+ it('should render', async () => {
+ // Arrange.
+ CoreIframeComponent.loadingTimeout = 0;
+
+ // Act.
+ const { nativeElement } = await renderTemplate(
+ CoreIframeComponent,
+ '',
+ );
+
+ // Assert.
+ expect(nativeElement.innerHTML.trim()).not.toHaveLength(0);
+
+ const iframe = nativeElement.querySelector('iframe');
+ expect(iframe).not.toBeNull();
+ expect(iframe.src).toEqual('https://moodle.org/');
+ });
});
diff --git a/src/core/components/tests/user-avatar.test.ts b/src/core/components/tests/user-avatar.test.ts
index a8d933837..7b4c5f12a 100644
--- a/src/core/components/tests/user-avatar.test.ts
+++ b/src/core/components/tests/user-avatar.test.ts
@@ -12,8 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import { CoreUserAvatarComponent } from '@components/user-avatar/user-avatar';
+
+import { renderComponent } from '@/testing/utils';
+
describe('CoreUserAvatarComponent', () => {
- it.todo('should render');
+ it('should render', async () => {
+ // Act.
+ const { nativeElement } = await renderComponent(CoreUserAvatarComponent);
+
+ // Assert.
+ expect(nativeElement.innerHTML.trim()).not.toHaveLength(0);
+
+ const image = nativeElement.querySelector('img');
+ expect(image).not.toBeNull();
+ expect(image.src).toEqual(document.location.href + 'assets/img/user-avatar.png');
+ });
});
diff --git a/src/core/directives/tests/format-text.test.ts b/src/core/directives/tests/format-text.test.ts
index 3bfc5afa8..aea7a5ded 100644
--- a/src/core/directives/tests/format-text.test.ts
+++ b/src/core/directives/tests/format-text.test.ts
@@ -13,34 +13,29 @@
// limitations under the License.
import { IonContent } from '@ionic/angular';
-import { NgZone } from '@angular/core';
import Faker from 'faker';
import { CoreConfig } from '@services/config';
-import { CoreDomUtils, CoreDomUtilsProvider } from '@services/utils/dom';
+import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
import { CoreFilepool } from '@services/filepool';
+import { CoreFilter } from '@features/filter/services/filter';
+import { CoreFilterHelper } from '@features/filter/services/filter-helper';
import { CoreFormatTextDirective } from '@directives/format-text';
import { CoreSite } from '@classes/site';
import { CoreSites } from '@services/sites';
-import { CoreUrlUtils, CoreUrlUtilsProvider } from '@services/utils/url';
-import { CoreUtils, CoreUtilsProvider } from '@services/utils/utils';
-import { Platform } from '@singletons';
+import { CoreUtils } from '@services/utils/utils';
-import { mock, mockSingleton, RenderConfig, renderWrapperComponent } from '@/testing/utils';
-import { CoreFilter } from '@features/filter/services/filter';
-import { CoreApp } from '@services/app';
+import { mock, mockSingleton, RenderConfig, renderTemplate, renderWrapperComponent } from '@/testing/utils';
describe('CoreFormatTextDirective', () => {
let config: Partial;
beforeEach(() => {
- mockSingleton(Platform, { ready: () => Promise.resolve() });
+ mockSingleton(CoreSites, { getSite: () => Promise.reject() });
mockSingleton(CoreConfig, { get: (_, defaultValue) => defaultValue });
-
- CoreDomUtils.setInstance(new CoreDomUtilsProvider());
- CoreUrlUtils.setInstance(new CoreUrlUtilsProvider());
- CoreUtils.setInstance(new CoreUtilsProvider(mock()));
+ mockSingleton(CoreFilter, { formatText: text => Promise.resolve(text) });
+ mockSingleton(CoreFilterHelper, { getFiltersAndFormatText: text => Promise.resolve({ text, filters: [] }) });
config = {
providers: [
@@ -53,9 +48,6 @@ describe('CoreFormatTextDirective', () => {
// Arrange
const sentence = Faker.lorem.sentence();
- mockSingleton(CoreSites, { getSite: () => Promise.reject() });
- mockSingleton(CoreFilter, { formatText: (text) => Promise.resolve(text) });
-
// Act
const fixture = await renderWrapperComponent(
CoreFormatTextDirective,
@@ -70,6 +62,63 @@ describe('CoreFormatTextDirective', () => {
expect(text.innerHTML).toEqual(sentence);
});
+ it('should format text', async () => {
+ // Arrange
+ mockSingleton(CoreFilter, { formatText: () => 'Formatted text' });
+
+ // Act
+ const { nativeElement } = await renderTemplate(
+ CoreFormatTextDirective,
+ '',
+ );
+
+ // Assert
+ const text = nativeElement.querySelector('core-format-text');
+ expect(text).not.toBeNull();
+ expect(text.textContent).toEqual('Formatted text');
+
+ expect(CoreFilter.formatText).toHaveBeenCalledTimes(1);
+ expect(CoreFilter.formatText).toHaveBeenCalledWith(
+ 'Lorem ipsum dolor',
+ expect.anything(),
+ expect.anything(),
+ undefined,
+ );
+ });
+
+ it('should get filters from server and format text', async () => {
+ // Arrange
+ mockSingleton(CoreFilterHelper, {
+ getFiltersAndFormatText: () => Promise.resolve({
+ text: 'Formatted text',
+ filters: [],
+ }),
+ });
+
+ // Act
+ const { nativeElement } = await renderTemplate(CoreFormatTextDirective, `
+
+ `);
+
+ // Assert
+ const text = nativeElement.querySelector('core-format-text');
+ expect(text).not.toBeNull();
+ expect(text.textContent).toEqual('Formatted text');
+
+ expect(CoreFilterHelper.getFiltersAndFormatText).toHaveBeenCalledTimes(1);
+ expect(CoreFilterHelper.getFiltersAndFormatText).toHaveBeenCalledWith(
+ 'Lorem ipsum dolor',
+ 'course',
+ 42,
+ expect.anything(),
+ undefined,
+ );
+ });
+
it('should use external-content directive on images', async () => {
// Arrange
const site = mock({
@@ -86,11 +135,9 @@ describe('CoreFormatTextDirective', () => {
getSite: () => Promise.resolve(site),
getCurrentSite: () => Promise.resolve(site),
});
- mockSingleton(CoreFilter, { formatText: (text) => Promise.resolve(text) });
- mockSingleton(CoreApp, { isMobile: () => false });
// Act
- const fixture = await renderWrapperComponent(
+ const { nativeElement } = await renderWrapperComponent(
CoreFormatTextDirective,
'core-format-text',
{ text: '
', siteId: site.getId() },
@@ -98,7 +145,7 @@ describe('CoreFormatTextDirective', () => {
);
// Assert
- const image = fixture.nativeElement.querySelector('img');
+ const image = nativeElement.querySelector('img');
expect(image).not.toBeNull();
expect(image.src).toEqual('file://local-path/');
@@ -106,10 +153,28 @@ describe('CoreFormatTextDirective', () => {
expect(CoreFilepool.getSrcByUrl).toHaveBeenCalledTimes(1);
});
- it.todo('should format text');
+ it('should use link directive on anchors', async () => {
+ // Arrange
+ mockSingleton(CoreContentLinksHelper, { handleLink: () => Promise.resolve(true) });
- it.todo('should get filters from server and format text');
+ // Act
+ const { nativeElement } = await renderWrapperComponent(
+ CoreFormatTextDirective,
+ 'core-format-text',
+ { text: 'Link' },
+ );
+ const anchor = nativeElement.querySelector('a');
- it.todo('should use link directive on anchors');
+ anchor.click();
+
+ // Assert
+ expect(CoreContentLinksHelper.handleLink).toHaveBeenCalledTimes(1);
+ expect(CoreContentLinksHelper.handleLink).toHaveBeenCalledWith(
+ 'https://anchor-url/',
+ undefined,
+ expect.anything(),
+ expect.anything(),
+ );
+ });
});
diff --git a/src/core/directives/tests/link.test.ts b/src/core/directives/tests/link.test.ts
index 00bdbab0f..891df6111 100644
--- a/src/core/directives/tests/link.test.ts
+++ b/src/core/directives/tests/link.test.ts
@@ -13,8 +13,9 @@
// limitations under the License.
import { CoreLinkDirective } from '@directives/link';
+import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
-import { renderTemplate } from '@/testing/utils';
+import { mockSingleton, renderTemplate } from '@/testing/utils';
describe('CoreLinkDirective', () => {
@@ -33,6 +34,28 @@ describe('CoreLinkDirective', () => {
expect(anchor.href).toEqual('https://moodle.org/');
});
- it.todo('should capture clicks');
+ it('should capture clicks', async () => {
+ // Arrange
+ mockSingleton(CoreContentLinksHelper, { handleLink: () => Promise.resolve(true) });
+
+ // Act
+ const { nativeElement } = await renderTemplate(
+ CoreLinkDirective,
+ 'Link',
+ );
+
+ const anchor = nativeElement.querySelector('a');
+
+ anchor.click();
+
+ // Assert
+ expect(CoreContentLinksHelper.handleLink).toHaveBeenCalledTimes(1);
+ expect(CoreContentLinksHelper.handleLink).toHaveBeenCalledWith(
+ 'https://moodle.org/',
+ undefined,
+ expect.anything(),
+ expect.anything(),
+ );
+ });
});