eintopf.info@v0.13.16/web/event_test.go (about)

     1  // Copyright (C) 2022 The Eintopf authors
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  
    16  package web
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"net/url"
    22  	"regexp"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/PuerkitoBio/goquery"
    28  	"github.com/google/go-cmp/cmp"
    29  	"github.com/iand/microdata"
    30  
    31  	"eintopf.info/service/event"
    32  	"eintopf.info/service/group"
    33  	"eintopf.info/service/place"
    34  	"eintopf.info/service/revent"
    35  )
    36  
    37  func TestEventPage(t *testing.T) {
    38  	tests := []routeTest{
    39  		{
    40  			name: "NotFound",
    41  			tz:   time.UTC,
    42  			uri:  "/event/12345",
    43  			events: []*event.NewEvent{
    44  				{
    45  					Published: true,
    46  					Name:      "foo",
    47  				},
    48  			},
    49  			status: 404,
    50  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
    51  				assertNodes(t, doc, ".error", []string{"404 Veranstaltung wurde nicht gefunden"})
    52  			},
    53  		},
    54  		{
    55  			name: "NotPublished",
    56  			tz:   time.UTC,
    57  			uri:  "/event/0",
    58  			events: []*event.NewEvent{
    59  				{
    60  					Published: false,
    61  					Name:      "foo",
    62  				},
    63  			},
    64  			status: 200,
    65  		},
    66  		{
    67  			name: "MetaNoIndexNotPublished",
    68  			tz:   time.UTC,
    69  			uri:  "/event/0",
    70  			events: []*event.NewEvent{
    71  				{
    72  					Published: false,
    73  					Name:      "foo",
    74  				},
    75  			},
    76  			status: 200,
    77  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
    78  				assertRobotsIndex(t, doc, "noindex, nofollow")
    79  			},
    80  		},
    81  		{
    82  			name: "MetaIndexPublished",
    83  			tz:   time.UTC,
    84  			uri:  "/event/0",
    85  			events: []*event.NewEvent{
    86  				{
    87  					Published: true,
    88  					Name:      "foo",
    89  				},
    90  			},
    91  			status: 200,
    92  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
    93  				assertRobotsIndex(t, doc, "index, follow")
    94  			},
    95  		},
    96  		{
    97  			name:   "MetaDefault",
    98  			tz:     time.UTC,
    99  			uri:    "/event/0",
   100  			themes: []string{"eintopf", "testdata/themes/meta"},
   101  			events: []*event.NewEvent{
   102  				{
   103  					Published: true,
   104  					Name:      "Foo",
   105  				},
   106  			},
   107  			status: 200,
   108  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
   109  				assertRobotsIndex(t, doc, "index, follow")
   110  				assertMeta(t, doc, MetaTags{
   111  					Title:       "Foo | Custom Sitename",
   112  					Description: "Custom Meta Description",
   113  					Image:       "/assets/images/logo.png",
   114  				})
   115  			},
   116  		},
   117  		{
   118  			name: "MetaContent",
   119  			tz:   time.UTC,
   120  			uri:  "/event/0",
   121  			events: []*event.NewEvent{
   122  				{
   123  					Published:   true,
   124  					Name:        "Foo",
   125  					Description: "Foo bar",
   126  					Image:       "Foobar.png",
   127  				},
   128  			},
   129  			status: 200,
   130  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
   131  				assertRobotsIndex(t, doc, "index, follow")
   132  				assertMeta(t, doc, MetaTags{
   133  					Title:       "Foo | Eintopf Stuttgart",
   134  					Description: "Foo bar",
   135  					Image:       "/api/v1/media/Foobar.png",
   136  				})
   137  			},
   138  		},
   139  		{
   140  			name: "Schema.orgEventMinimal",
   141  			tz:   time.UTC,
   142  			uri:  "/event/0",
   143  			events: []*event.NewEvent{
   144  				{
   145  					Published:   true,
   146  					Name:        "Foo",
   147  					Description: "Foo bar",
   148  					Start:       time.Date(2022, 10, 5, 14, 30, 0, 0, time.UTC),
   149  				},
   150  			},
   151  			status: 200,
   152  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
   153  				var html, err = doc.Html()
   154  				if err != nil {
   155  					tt.Errorf(err.Error())
   156  				}
   157  
   158  				baseUrl, _ := url.Parse("http://localhost/")
   159  				p := microdata.NewParser(strings.NewReader(html), baseUrl)
   160  				data, err := p.Parse()
   161  				if err != nil {
   162  					tt.Errorf(err.Error())
   163  				}
   164  
   165  				pageMicrodataJSON, err := data.JSON()
   166  				if err != nil {
   167  					t.Errorf(`JSON marshal failed for pageMicrodataJSON`)
   168  				}
   169  
   170  				testMicrodataItem := microdata.NewItem()
   171  				testMicrodataItem.AddType("https://schema.org/Event")
   172  				testMicrodataItem.AddString("name", "Foo")
   173  				testMicrodataItem.AddString("description", "Foo bar")
   174  				testMicrodataItem.AddString("startDate", "2022-10-05T14:30:00Z")
   175  				testMicrodata := microdata.NewMicrodata()
   176  				testMicrodata.AddItem(testMicrodataItem)
   177  				testMicrodataJSON, err := testMicrodata.JSON()
   178  				if err != nil {
   179  					t.Errorf(`JSON marshal failed for testMicrodataJSON`)
   180  				}
   181  
   182  				if diff := cmp.Diff(string(testMicrodataJSON), string(pageMicrodataJSON)); diff != "" {
   183  					t.Errorf(`schema event content mismatch (-want +got):\n%s`, diff)
   184  				}
   185  			},
   186  		},
   187  		{
   188  			name: "Schema.orgEventMaximum",
   189  			tz:   time.UTC,
   190  			uri:  "/event/0",
   191  			events: []*event.NewEvent{
   192  				{
   193  					Published:   true,
   194  					Name:        "Foo",
   195  					Description: "Foo bar",
   196  					Start:       time.Date(2022, 10, 5, 14, 30, 0, 0, time.UTC),
   197  					End:         tptr(time.Date(2022, 10, 5, 20, 30, 0, 0, time.UTC)),
   198  					Location:    "bar",
   199  					Organizers:  []string{"dada"},
   200  				},
   201  			},
   202  			status: 200,
   203  			htmlTestFunc: func(tt *testing.T, doc *goquery.Document) {
   204  				var html, err = doc.Html()
   205  				if err != nil {
   206  					tt.Errorf(err.Error())
   207  				}
   208  
   209  				baseUrl, _ := url.Parse("http://localhost/")
   210  				p := microdata.NewParser(strings.NewReader(html), baseUrl)
   211  				data, err := p.Parse()
   212  				if err != nil {
   213  					tt.Errorf(err.Error())
   214  				}
   215  
   216  				pageMicrodataJSON, err := data.JSON()
   217  				if err != nil {
   218  					t.Errorf(`JSON marshal failed for pageMicrodataJSON`)
   219  				}
   220  
   221  				testMicrodataItemLocation := microdata.NewItem()
   222  				testMicrodataItemLocation.AddType("https://schema.org/Place")
   223  				testMicrodataItemLocation.AddString("name", "bar")
   224  
   225  				testMicrodataItem := microdata.NewItem()
   226  				testMicrodataItem.AddType("https://schema.org/Event")
   227  				testMicrodataItem.AddString("name", "Foo")
   228  				testMicrodataItem.AddString("description", "Foo bar")
   229  				testMicrodataItem.AddString("startDate", "2022-10-05T14:30:00Z")
   230  				testMicrodataItem.AddString("endDate", "2022-10-05T20:30:00Z")
   231  				testMicrodataItem.AddItem("location", testMicrodataItemLocation)
   232  				testMicrodataItem.AddString("organizer", "dada")
   233  
   234  				testMicrodata := microdata.NewMicrodata()
   235  				testMicrodata.AddItem(testMicrodataItem)
   236  				testMicrodataJSON, err := testMicrodata.JSON()
   237  				if err != nil {
   238  					t.Errorf(`JSON marshal failed for testMicrodataJSON`)
   239  				}
   240  
   241  				if diff := cmp.Diff(string(testMicrodataJSON), string(pageMicrodataJSON)); diff != "" {
   242  					t.Errorf(`schema event content mismatch (-want +got):\n%s`, diff)
   243  				}
   244  			},
   245  		},
   246  		{
   247  			name: "Canceled",
   248  			tz:   time.UTC,
   249  			uri:  "/event/0",
   250  			events: []*event.NewEvent{
   251  				{
   252  					Published: true,
   253  					Name:      "foo",
   254  				},
   255  			},
   256  			transform: func(eventService event.Storer, groupService group.Service, placeService place.Service) error {
   257  				_, err := eventService.Update(context.Background(), &event.Event{
   258  					ID:        "0",
   259  					Published: true,
   260  					Canceled:  true,
   261  					Name:      "foo",
   262  				})
   263  				return err
   264  			},
   265  			status: 200,
   266  			contentTestFunc: func(t *testing.T, content string) {
   267  				if !strings.Contains(content, "Fällt aus") {
   268  					t.Error("should contain 'Fällt aus'")
   269  				}
   270  			},
   271  		},
   272  		{
   273  			name: "NoEndDate",
   274  			tz:   time.UTC,
   275  			uri:  "/event/0",
   276  			events: []*event.NewEvent{
   277  				{
   278  					Published: true,
   279  					Name:      "foo",
   280  					Start:     time.Date(2022, 10, 5, 14, 30, 0, 0, time.UTC),
   281  				},
   282  			},
   283  			status: 200,
   284  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   285  				assertInfoDate(t, doc, "05.10.2022 14:30 Uhr")
   286  			},
   287  		},
   288  		{
   289  			name: "WithEndDateSameDay",
   290  			tz:   time.UTC,
   291  			uri:  "/event/0",
   292  			events: []*event.NewEvent{
   293  				{
   294  					Published: true,
   295  					Name:      "foo",
   296  					Start:     time.Date(2022, 10, 5, 14, 30, 0, 0, time.UTC),
   297  					End:       tptr(time.Date(2022, 10, 5, 16, 30, 0, 0, time.UTC)),
   298  				},
   299  			},
   300  			status: 200,
   301  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   302  				assertInfoDate(t, doc, "05.10.2022 14:30 Uhr - 16:30 Uhr")
   303  			},
   304  		},
   305  		{
   306  			name: "WithEndDateNotSameDay",
   307  			tz:   time.UTC,
   308  			uri:  "/event/0",
   309  			events: []*event.NewEvent{
   310  				{
   311  					Published: true,
   312  					Name:      "foo",
   313  					Start:     time.Date(2022, 10, 5, 14, 30, 0, 0, time.UTC),
   314  					End:       tptr(time.Date(2022, 10, 7, 16, 30, 0, 0, time.UTC)),
   315  				},
   316  			},
   317  			status: 200,
   318  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   319  				assertInfoDate(t, doc, "05.10.2022 14:30 Uhr - 07.10.2022 16:30 Uhr")
   320  			},
   321  		},
   322  		{
   323  			name: "NoOrganizers",
   324  			tz:   time.UTC,
   325  			uri:  "/event/0",
   326  			events: []*event.NewEvent{
   327  				{
   328  					Published:  true,
   329  					Name:       "foo",
   330  					Organizers: []string{},
   331  				},
   332  			},
   333  			status: 200,
   334  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   335  				assertInfoOrganizers(t, doc, "")
   336  			},
   337  		},
   338  		{
   339  			name: "OneOrganizer",
   340  			tz:   time.UTC,
   341  			uri:  "/event/0",
   342  			events: []*event.NewEvent{
   343  				{
   344  					Published:  true,
   345  					Name:       "foo",
   346  					Organizers: []string{"dada"},
   347  				},
   348  			},
   349  			status: 200,
   350  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   351  				assertInfoOrganizers(t, doc, "dada")
   352  			},
   353  		},
   354  		{
   355  			name: "MultipleOrganizer",
   356  			tz:   time.UTC,
   357  			uri:  "/event/0",
   358  			events: []*event.NewEvent{
   359  				{
   360  					Published:  true,
   361  					Name:       "foo",
   362  					Organizers: []string{"dada", "baba"},
   363  				},
   364  			},
   365  			status: 200,
   366  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   367  				assertInfoOrganizers(t, doc, "dada, baba")
   368  			},
   369  		},
   370  		{
   371  			name: "Involved",
   372  			tz:   time.UTC,
   373  			uri:  "/event/0",
   374  			events: []*event.NewEvent{
   375  				{
   376  					Published: true,
   377  					Name:      "foo",
   378  					Involved:  []event.Involved{{Name: "foo", Description: "descfoo"}, {Name: "bar", Description: "descbar"}},
   379  				},
   380  			},
   381  			status: 200,
   382  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   383  				elementsName := doc.Find(`.info-involved .info-data`)
   384  				elementsDescription := doc.Find(`.description`)
   385  				if elementsName.Length() != 2 {
   386  					t.Errorf(`Expected 2 involved, got %d`, elementsName.Length())
   387  				}
   388  				if diff := cmp.Diff("foobar", elementsName.Text()); diff != "" {
   389  					t.Errorf(`Involved content mismatch (-want +got):\n%s`, diff)
   390  				}
   391  				if elementsDescription.Length() != 2 {
   392  					t.Errorf(`Expected 2 involved descriptions, got %d`, elementsDescription.Length())
   393  				}
   394  				if diff := cmp.Diff("descfoodescbar", elementsDescription.Text()); diff != "" {
   395  					t.Errorf(`Involved description content mismatch (-want +got):\n%s`, diff)
   396  				}
   397  			},
   398  		},
   399  		{
   400  			name: "Location",
   401  			tz:   time.UTC,
   402  			uri:  "/event/0",
   403  			events: []*event.NewEvent{
   404  				{
   405  					Published: true,
   406  					Name:      "foo",
   407  					Location:  "bar",
   408  				},
   409  			},
   410  			status: 200,
   411  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   412  				assertInfoLocation(t, doc, "bar", "")
   413  			},
   414  		},
   415  		{
   416  			name: "LocationAndLocation2",
   417  			tz:   time.UTC,
   418  			uri:  "/event/0",
   419  			events: []*event.NewEvent{
   420  				{
   421  					Published: true,
   422  					Name:      "foo",
   423  					Location:  "bar",
   424  					Location2: "bar2",
   425  				},
   426  			},
   427  			status: 200,
   428  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   429  				assertInfoLocation(t, doc, "bar", "bar2")
   430  			},
   431  		},
   432  		{
   433  			name: "Children",
   434  			tz:   time.UTC,
   435  			uri:  "/event/0",
   436  			events: []*event.NewEvent{
   437  				{
   438  					Published: true,
   439  					Name:      "foo",
   440  				},
   441  				{
   442  					Parent:    "id:0",
   443  					Published: true,
   444  					Name:      "bar",
   445  					Start:     time.Date(2022, 9, 8, 10, 0, 0, 0, time.UTC),
   446  				},
   447  				{
   448  					Parent:    "id:0",
   449  					Published: true,
   450  					Name:      "baz",
   451  					Start:     time.Date(2022, 9, 9, 10, 0, 0, 0, time.UTC),
   452  				},
   453  			},
   454  			status: 200,
   455  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   456  				assertNodes(t, doc, "h2", []string{"Programm 08. Sep / Donnerstag", "Programm 09. Sep / Freitag"})
   457  			},
   458  		},
   459  		{
   460  			name: "WithMap",
   461  			tz:   time.UTC,
   462  			uri:  "/event/0",
   463  			events: []*event.NewEvent{
   464  				{
   465  					Published: true,
   466  					Name:      "foo",
   467  					Location:  "id:0",
   468  				},
   469  			},
   470  			places: []*place.NewPlace{
   471  				{
   472  					Published: true,
   473  					Name:      "bar",
   474  					Lat:       1,
   475  					Lng:       2,
   476  				},
   477  			},
   478  			status: 200,
   479  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   480  				assertMap(t, doc)
   481  			},
   482  		},
   483  		{
   484  			name: "WithoutMap NoLocation",
   485  			tz:   time.UTC,
   486  			uri:  "/event/0",
   487  			events: []*event.NewEvent{
   488  				{
   489  					Published: true,
   490  					Name:      "foo",
   491  				},
   492  			},
   493  			status: 200,
   494  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   495  				assertNoMap(t, doc)
   496  			},
   497  		},
   498  		{
   499  			name: "WithoutMap NoPlace",
   500  			tz:   time.UTC,
   501  			uri:  "/event/0",
   502  			events: []*event.NewEvent{
   503  				{
   504  					Published: true,
   505  					Name:      "foo",
   506  					Location:  "bar",
   507  				},
   508  			},
   509  			status: 200,
   510  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   511  				assertNoMap(t, doc)
   512  			},
   513  		},
   514  		{
   515  			name: "WithoutMap NoLatLng",
   516  			tz:   time.UTC,
   517  			uri:  "/event/0",
   518  			events: []*event.NewEvent{
   519  				{
   520  					Published: true,
   521  					Name:      "foo",
   522  					Location:  "id:0",
   523  				},
   524  			},
   525  			places: []*place.NewPlace{
   526  				{
   527  					Published: true,
   528  					Name:      "bar",
   529  				},
   530  			},
   531  			status: 200,
   532  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   533  				assertNoMap(t, doc)
   534  			},
   535  		},
   536  		{
   537  			name: "PastEvents",
   538  			uri:  "/event/0",
   539  			events: []*event.NewEvent{
   540  				{
   541  					Published:  true,
   542  					Name:       "my event",
   543  					Organizers: []string{"id:0"},
   544  				},
   545  				// Included
   546  				{
   547  					Published:  true,
   548  					Name:       "past",
   549  					Organizers: []string{"id:0"},
   550  					Start:      time.Now().Add(-1 * time.Hour * 24),
   551  				},
   552  				{
   553  					Published:  true,
   554  					Name:       "multiday",
   555  					Organizers: []string{"id:0"},
   556  					Start:      time.Now().Add(-1 * time.Hour * 24),
   557  					End:        tptr(time.Now().Add(-1 * time.Hour * 24 * 4)),
   558  				},
   559  				// Not included
   560  				{
   561  					Published:  true,
   562  					Name:       "another group",
   563  					Organizers: []string{"id:1"},
   564  					Start:      time.Now().Add(-1 * time.Hour * 24),
   565  				},
   566  				{
   567  					Published:  true,
   568  					Name:       "future",
   569  					Organizers: []string{"id:0"},
   570  					Start:      time.Now().Add(time.Hour * 24),
   571  				},
   572  				{
   573  					Published:  false,
   574  					Name:       "not published",
   575  					Organizers: []string{"id:0"},
   576  					Start:      time.Now().Add(-1 * time.Hour * 24),
   577  				},
   578  			},
   579  			groups: []*group.NewGroup{
   580  				{
   581  					Published: true,
   582  					Name:      "group1",
   583  				},
   584  				{
   585  					Published: true,
   586  					Name:      "group2",
   587  				},
   588  			},
   589  			status: 200,
   590  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   591  				assertPastEvents(t, doc, []string{"past", "multiday"})
   592  			},
   593  		},
   594  		{
   595  			name: "FutureEvents",
   596  			uri:  "/event/0",
   597  			events: []*event.NewEvent{
   598  				{
   599  					Published:  true,
   600  					Name:       "my event",
   601  					Organizers: []string{"id:0"},
   602  				},
   603  				// Included
   604  				{
   605  					Published:  true,
   606  					Name:       "future",
   607  					Organizers: []string{"id:0"},
   608  					Start:      time.Now().Add(time.Hour * 24 * 2),
   609  				},
   610  				{
   611  					Published:  true,
   612  					Name:       "multiday",
   613  					Organizers: []string{"id:0"},
   614  					Start:      time.Now().Add(time.Hour * 24 * 2),
   615  					End:        tptr(time.Now().Add(time.Hour * 24 * 4)),
   616  				},
   617  				// Not inlcuded
   618  				{
   619  					Published:  true,
   620  					Name:       "another group",
   621  					Organizers: []string{"id:1"},
   622  					Start:      time.Now().Add(-1 * time.Hour * 24),
   623  				},
   624  				{
   625  					Published:  true,
   626  					Name:       "past",
   627  					Organizers: []string{"id:0"},
   628  					Start:      time.Now().Add(-1 * time.Hour * 24),
   629  				},
   630  				{
   631  					Published:  false,
   632  					Name:       "not published",
   633  					Organizers: []string{"id:0"},
   634  					Start:      time.Now().Add(time.Hour * 24 * 2),
   635  				},
   636  			},
   637  			groups: []*group.NewGroup{
   638  				{
   639  					Published: true,
   640  					Name:      "group1",
   641  				},
   642  				{
   643  					Published: true,
   644  					Name:      "group2",
   645  				},
   646  			},
   647  			status: 200,
   648  			htmlTestFunc: func(t *testing.T, doc *goquery.Document) {
   649  				assertFutureEvents(t, doc, []string{"future", "multiday"})
   650  			},
   651  		},
   652  	}
   653  
   654  	testRoutes(t, tests)
   655  }
   656  
   657  func assertInfoDate(t *testing.T, doc *goquery.Document, date string) {
   658  	t.Helper()
   659  	if diff := cmp.Diff(1, len(doc.Find(".info-date").Nodes)); diff != "" {
   660  		t.Errorf(".info-date mismatch (-want +got):\n%s", diff)
   661  	}
   662  	if diff := cmp.Diff(date, removeWhiteSpace(doc.Find(".info-date .info-data").Text())); diff != "" {
   663  		t.Errorf(".info-date .info-data mismatch (-want +got):\n%s", diff)
   664  	}
   665  }
   666  
   667  func assertInfoOrganizers(t *testing.T, doc *goquery.Document, organizers string) {
   668  	t.Helper()
   669  	if organizers == "" {
   670  		if diff := cmp.Diff(0, len(doc.Find(".info-organizers").Nodes)); diff != "" {
   671  			t.Errorf(".info-organizers mismatch (-want +got):\n%s", diff)
   672  		}
   673  	} else {
   674  		if diff := cmp.Diff(1, len(doc.Find(".info-organizers").Nodes)); diff != "" {
   675  			t.Errorf(".info-organizers mismatch (-want +got):\n%s", diff)
   676  		}
   677  		if diff := cmp.Diff(organizers, removeWhiteSpace(doc.Find(".info-organizers .info-data").Text())); diff != "" {
   678  			t.Errorf(".info-organizers .info-data mismatch (-want +got):\n%s", diff)
   679  		}
   680  	}
   681  }
   682  
   683  func assertInfoLocation(t *testing.T, doc *goquery.Document, location string, location2 string) {
   684  	t.Helper()
   685  	if location == "" {
   686  		if diff := cmp.Diff(1, len(doc.Find(".info-location").Text())); diff != "" {
   687  			t.Errorf(".info-location mismatch (-want +got):\n%s", diff)
   688  		}
   689  		if location2 == "" {
   690  			if diff := cmp.Diff(location, doc.Find(".info-location .info-data").Text()); diff != "" {
   691  				t.Errorf(".info-location .info-data mismatch (-want +got):\n%s", diff)
   692  			}
   693  		} else {
   694  			if diff := cmp.Diff(fmt.Sprintf("%s, %s", location, location2), doc.Find(".info-location .info-data").Text()); diff != "" {
   695  				t.Errorf(".info-location .info-data mismatch (-want +got):\n%s", diff)
   696  			}
   697  		}
   698  	}
   699  }
   700  
   701  func removeWhiteSpace(s string) string {
   702  	noLineBreaks := strings.ReplaceAll(s, "\n", "")
   703  	noTabs := strings.ReplaceAll(noLineBreaks, "    ", "")
   704  	space := regexp.MustCompile(`\s+`)
   705  	return strings.TrimSpace(space.ReplaceAllString(noTabs, " "))
   706  }
   707  
   708  func tptr(t time.Time) *time.Time {
   709  	return &t
   710  }
   711  
   712  func TestFormartInterval(t *testing.T) {
   713  	tests := []struct {
   714  		interval revent.Interval
   715  		want     string
   716  	}{
   717  		{
   718  			interval: revent.Interval{
   719  				Type:     revent.IntervalWeek,
   720  				Interval: 1,
   721  				WeekDay:  time.Monday,
   722  			},
   723  			want: "Jede Woche Montag",
   724  		},
   725  	}
   726  	for _, tc := range tests {
   727  		if formatInterval(tc.interval) != tc.want {
   728  			t.Errorf("want: %s, got: %s", tc.want, formatInterval(tc.interval))
   729  		}
   730  	}
   731  }
   732  
   733  func stringContains(slice []string, item string) bool {
   734  	set := make(map[string]struct{}, len(slice))
   735  	for _, s := range slice {
   736  		set[s] = struct{}{}
   737  	}
   738  
   739  	_, ok := set[item]
   740  	return ok
   741  }